解决linux5.15编译时不生成boot.img 的问题

平台:rk3399 (与平台关系不大)

内核 :linux5.15

下一个linux5.15的内核,编译的时候

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j6 rk3399-rock960.img

目标rk3399-rock960.img 需要在arch/arm64/boot/dts/rockchip/ 目录下存在rk3399-rock960.dts文件 ,如果不存在,可以使用其他的dts文件作为目标。

错误提示1:(没法编译img这个目标)

make: *** No rule to make target 'rk3399-rock960.img'. Stop.

解决1:

修改arch/arm64/Makefile,在文件末尾增加一段(其他的内容不变)

MAKE_MODULES ?= y

%.img:

ifeq ("(CONFIG_MODULES)(MAKE_MODULES)(srctree)","yy(objtree)")

(Q)(MAKE) rockchip/$*.dtb Image.lz4 modules

else

(Q)(MAKE) rockchip/$*.dtb Image.lz4

endif

(Q)(srctree)/scripts/mkimg --dtb $*.dtb

CLEAN_DIRS += out

CLEAN_FILES += boot.img kernel.img resource.img zboot.img

再执行上面的make命令,该错误就没有了。

错误提示2:没有mkimg命令

解决:

从原(rk3399)sdk的内核中拷贝过来,这是个脚本文件。

cp ../kernel/scripts/mkimg scripts/

shell脚本内容如下:

bash 复制代码
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd.

set -e

usage() {
	cat >&2 << USAGE
usage: $0 [-h] --dtb DTB

optional arguments:
  -h, --help            show this help message and exit
  --dtb DTB             the dtb file name
USAGE
}

# Parse command-line arguments
while [ $# -gt 0 ]; do
	case $1 in
		--dtb)
			DTB=$2
			shift 2
			;;
		-h)
			usage
			exit 0
			;;
		--help)
			usage
			exit 0
			;;
		*)
			shift
			;;
        esac
done

srctree=${srctree-"."}
objtree=${objtree-"."}
if [ "${ARCH}" == "" ]; then
	if [ "$($srctree/scripts/config --state CONFIG_ARM)" == "y" ]; then
		ARCH=arm
	else
		ARCH=arm64
	fi
fi

LOGO_PATH=${srctree}/logo.bmp
[ -f ${LOGO_PATH} ] && LOGO=logo.bmp

LOGO_KERNEL_PATH=${srctree}/logo_kernel.bmp
[ -f ${LOGO_KERNEL_PATH} ] && LOGO_KERNEL=logo_kernel.bmp

KERNEL_IMAGE_PATH=${objtree}/arch/${ARCH}/boot/Image
KERNEL_IMAGE_ARG="--kernel ${KERNEL_IMAGE_PATH}"
if [ "${ARCH}" == "arm" ]; then
	DTB_PATH=${objtree}/arch/arm/boot/dts/${DTB}
	ZIMAGE=zImage
else
	DTB_PATH=${objtree}/arch/arm64/boot/dts/rockchip/${DTB}
	ZIMAGE=Image.lz4
fi
KERNEL_ZIMAGE_PATH=${objtree}/arch/${ARCH}/boot/${ZIMAGE}
KERNEL_ZIMAGE_ARG="--kernel ${KERNEL_ZIMAGE_PATH}"
if [ ! -f ${DTB_PATH} ]; then
	echo "No dtb" >&2
	usage
	exit 1
fi

OUT=out
ITB=${BOOT_IMG}
ITS=${OUT}/boot.its
MKIMAGE=${MKIMAGE-"mkimage"}
MKIMAGE_ARG="-E -p 0x800"

make_boot_img()
{
	RAMDISK_IMG_PATH=${objtree}/ramdisk.img
	[ -f ${RAMDISK_IMG_PATH} ] && RAMDISK_IMG=ramdisk.img && RAMDISK_ARG="--ramdisk ${RAMDISK_IMG_PATH}"

	${srctree}/scripts/mkbootimg \
		${KERNEL_IMAGE_ARG} \
		${RAMDISK_ARG} \
		--second resource.img \
		-o boot.img && \
	echo "  Image:  boot.img (with Image ${RAMDISK_IMG} resource.img) is ready";
	${srctree}/scripts/mkbootimg \
		${KERNEL_ZIMAGE_ARG} \
		${RAMDISK_ARG} \
		--second resource.img \
		-o zboot.img && \
	echo "  Image:  zboot.img (with ${ZIMAGE} ${RAMDISK_IMG} resource.img) is ready"
}
make_boot_multi_dtb_img()
{
	RAMDISK_IMG_PATH=${objtree}/ramdisk.img
	[ -f ${RAMDISK_IMG_PATH} ] && RAMDISK_IMG=ramdisk.img && RAMDISK_ARG="--ramdisk ${RAMDISK_IMG_PATH}"

	${srctree}/scripts/mkbootimg \
		${KERNEL_IMAGE_ARG} \
		${RAMDISK_ARG} \
		--second resource_multi_dtb.img \
		-o boot.img && \
	echo "  Image:  boot.img (with Image ${RAMDISK_IMG} resource_multi_dtb.img) is ready";
	${srctree}/scripts/mkbootimg \
		${KERNEL_ZIMAGE_ARG} \
		${RAMDISK_ARG} \
		--second resource_multi_dtb.img \
		-o zboot.img && \
	echo "  Image:  zboot.img (with ${ZIMAGE} ${RAMDISK_IMG} resource_multi_dtb.img) is ready"
}

repack_boot_img()
{
	${srctree}/scripts/repack-bootimg \
		--boot_img ${BOOT_IMG} --out ${OUT} \
		${KERNEL_IMAGE_ARG} \
		--second resource.img \
		--dtb ${DTB_PATH} \
		-o boot.img &&
	echo "  Image:  boot.img (${BOOT_IMG} + Image) is ready";
	${srctree}/scripts/repack-bootimg \
		--boot_img ${BOOT_IMG} --out ${OUT} \
		${KERNEL_ZIMAGE_ARG} \
		--second resource.img \
		--dtb ${DTB_PATH} \
		-o zboot.img && \
	echo "  Image:  zboot.img (${BOOT_IMG} + ${ZIMAGE}) is ready"
}

repack_multi_dtb_boot_img()
{
	${srctree}/scripts/repack-bootimg \
		--boot_img ${BOOT_IMG} --out ${OUT} \
		${KERNEL_IMAGE_ARG} \
		--second resource_multi_dtb.img \
		--dtb ${DTB_PATH} \
		-o boot.img &&
	echo "  Image:  boot.img (${BOOT_IMG} + Image + resource_multi_dtb) is ready";
	${srctree}/scripts/repack-bootimg \
		--boot_img ${BOOT_IMG} --out ${OUT} \
		${KERNEL_ZIMAGE_ARG} \
		--second resource_multi_dtb.img \
		--dtb ${DTB_PATH} \
		-o zboot.img && \
	echo "  Image:  zboot.img (${BOOT_IMG} + ${ZIMAGE}) is ready"
}


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

unpack_itb()
{
	rm -rf ${OUT}
	mkdir -p ${OUT}

	for NAME in $(fdtget -l ${ITB} /images)
	do
		# generate image
		NODE="/images/${NAME}"
		OFFS=$(fdtget -ti ${ITB} ${NODE} data-position)
		SIZE=$(fdtget -ti ${ITB} ${NODE} data-size)
		if [ -z ${OFFS} ]; then
			continue;
		fi

		if [ ${SIZE} -ne 0 ]; then
			dd if=${ITB} of=${OUT}/${NAME} bs=${SIZE} count=1 skip=${OFFS} iflag=skip_bytes >/dev/null 2>&1
		else
			touch ${OUT}/${NAME}
		fi
	done

	[ ! -f ${OUT}/kernel ] && echo "FIT ${ITB} no kernel" >&2 && exit 1 || true
}

gen_its()
{
	TMP_ITB=${OUT}/boot.tmp

	# add placeholder
	cp ${ITB} ${TMP_ITB}
	for NAME in $(fdtget -l ${ITB} /images); do
		fdtput -t s ${TMP_ITB} /images/${NAME} data "/INCBIN/(${NAME})"
	done
	dtc -I dtb -O dts ${TMP_ITB} -o ${ITS} >/dev/null 2>&1
	rm -f ${TMP_ITB}

	# fixup placeholder: data = "/INCBIN/(...)"; -> data = /incbin/("...");
	sed -i "s/\"\/INCBIN\/(\(.*\))\"/\/incbin\/(\"\1\")/" ${ITS}

	# remove
	sed -i "/memreserve/d"		${ITS}
	sed -i "/timestamp/d"		${ITS}
	sed -i "/data-size/d"		${ITS}
	sed -i "/data-position/d"	${ITS}
	sed -i "/value/d"		${ITS}
	sed -i "/hashed-strings/d"	${ITS}
	sed -i "/hashed-nodes/d"	${ITS}
	sed -i "/signer-version/d"	${ITS}
	sed -i "/signer-name/d"		${ITS}
}

gen_itb()
{
	[ -f ${OUT}/fdt ] && cp -a ${DTB_PATH} ${OUT}/fdt && FDT=" + ${DTB}"
	[ -f ${OUT}/resource ] && cp -a resource.img ${OUT}/resource && RESOURCE=" + resource.img"
	COMP=$(fdtget ${ITB} /images/kernel compression)
	case "${COMP}" in
		gzip)	EXT=".gz";;
		lz4)	EXT=".lz4";;
		bzip2)	EXT=".bz2";;
		lzma)	EXT=".lzma";;
		lzo)	EXT=".lzo";;
	esac
	cp -a ${KERNEL_IMAGE_PATH}${EXT} ${OUT}/kernel && \
	${MKIMAGE} ${MKIMAGE_ARG} -f ${ITS} boot.img >/dev/null && \
	echo "  Image:  boot.img (FIT ${BOOT_IMG} + Image${EXT}${FDT}${RESOURCE}) is ready";
	if [ "${EXT}" == "" ] && [ -f ${KERNEL_ZIMAGE_PATH} ]; then
		cp -a ${KERNEL_ZIMAGE_PATH} ${OUT}/kernel && \
		${MKIMAGE} ${MKIMAGE_ARG} -f ${ITS} zboot.img >/dev/null && \
		echo "  Image:  zboot.img (FIT ${BOOT_IMG} + zImage${FDT}${RESOURCE}) is ready";
	fi
}

repack_itb()
{
	check_mkimage
	unpack_itb
	gen_its
	gen_itb
}

# Create U-Boot FIT Image use ${BOOT_ITS}
make_fit_boot_img()
{
	ITS=${OUT}/boot.its

	check_mkimage
	mkdir -p ${OUT}
	rm -f ${OUT}/fdt ${OUT}/kernel ${OUT}/resource ${ITS}

	cp -a ${BOOT_ITS} ${ITS}
	cp -a ${DTB_PATH} ${OUT}/fdt
	cp -a ${KERNEL_ZIMAGE_PATH} ${OUT}/kernel
	cp -a resource.img ${OUT}/resource

	if [ "${ARCH}" == "arm64" ]; then
		sed -i -e 's/arch = ""/arch = "arm64"/g' -e 's/compression = ""/compression = "lz4"/' ${ITS}
	else
		sed -i -e 's/arch = ""/arch = "arm"/g' -e 's/compression = ""/compression = "none"/' ${ITS}
	fi
	FIT_DESC=$(${MKIMAGE} ${MKIMAGE_ARG} -f ${ITS} boot.img | grep "FIT description" | sed 's/FIT description: //')
	echo "  Image:  boot.img (${FIT_DESC}) is ready";
}

if [ -x ${srctree}/scripts/bmpconvert ]; then
	if [ -f ${LOGO_PATH} ]; then
		${srctree}/scripts/bmpconvert ${LOGO_PATH};
	fi
	if [ -f ${LOGO_KERNEL_PATH} ]; then
		${srctree}/scripts/bmpconvert ${LOGO_KERNEL_PATH};
	fi
fi

if [ "${srctree}" != "${objtree}" ]; then
	if [ -f ${LOGO_PATH} ]; then
		cp -a ${LOGO_PATH} ${objtree}/;
	fi
	if [ -f ${LOGO_KERNEL_PATH} ]; then
		cp -a ${LOGO_KERNEL_PATH} ${objtree}/;
	fi
fi
scripts/resource_tool ${DTB_PATH} ${LOGO} ${LOGO_KERNEL} >/dev/null
echo "  Image:  resource.img (with ${DTB} ${LOGO} ${LOGO_KERNEL}) is ready"

if [ -f "${BOOT_IMG}" ]; then
	if file -L -p -b ${BOOT_IMG} | grep -q 'Device Tree Blob' ; then
		repack_itb;
	elif [ -x ${srctree}/scripts/repack-bootimg ]; then
		if [[ $MULTI_DTB = "true" ]] ; then
			echo "  ready to build multi dtb boot.img";
			repack_multi_dtb_boot_img;
		else
			repack_boot_img;
		fi
	fi
elif [ -f "${BOOT_ITS}" ]; then
	make_fit_boot_img;
elif [ -x ${srctree}/scripts/mkbootimg ]; then
		if [[ $MULTI_DTB = "true" ]] ; then
			echo "  ready to build multi dtb boot.img";
			make_boot_multi_dtb_img;
		else
			make_boot_img;
		fi
fi

错误提示3:没有resource_tool命令

解决:

  1. 从原sdk中拷贝c文件(当然可以直接拷贝二进程执行文件,拷贝二进制就不用修改makefile了)

cp ../kernel/scripts/resource_tool.c scripts/

resource_tool.c原文如下:

cpp 复制代码
// SPDX-License-Identifier: GPL-2.0+
/*
 * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd
 */

#include <errno.h>
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <time.h>

/**
 * \brief	   SHA-1 context structure
 */
typedef struct
{
    unsigned long total[2];	/*!< number of bytes processed	*/
    unsigned long state[5];	/*!< intermediate digest state	*/
    unsigned char buffer[64];	/*!< data block being processed */
}
sha1_context;

/*
 * 32-bit integer manipulation macros (big endian)
 */
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) {				\
	(n) = ( (unsigned long) (b)[(i)    ] << 24 )	\
	    | ( (unsigned long) (b)[(i) + 1] << 16 )	\
	    | ( (unsigned long) (b)[(i) + 2] <<  8 )	\
	    | ( (unsigned long) (b)[(i) + 3]       );	\
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) {				\
	(b)[(i)    ] = (unsigned char) ( (n) >> 24 );	\
	(b)[(i) + 1] = (unsigned char) ( (n) >> 16 );	\
	(b)[(i) + 2] = (unsigned char) ( (n) >>  8 );	\
	(b)[(i) + 3] = (unsigned char) ( (n)       );	\
}
#endif

/*
 * SHA-1 context setup
 */
static
void sha1_starts (sha1_context * ctx)
{
	ctx->total[0] = 0;
	ctx->total[1] = 0;

	ctx->state[0] = 0x67452301;
	ctx->state[1] = 0xEFCDAB89;
	ctx->state[2] = 0x98BADCFE;
	ctx->state[3] = 0x10325476;
	ctx->state[4] = 0xC3D2E1F0;
}

static void sha1_process(sha1_context *ctx, const unsigned char data[64])
{
	unsigned long temp, W[16], A, B, C, D, E;

	GET_UINT32_BE (W[0], data, 0);
	GET_UINT32_BE (W[1], data, 4);
	GET_UINT32_BE (W[2], data, 8);
	GET_UINT32_BE (W[3], data, 12);
	GET_UINT32_BE (W[4], data, 16);
	GET_UINT32_BE (W[5], data, 20);
	GET_UINT32_BE (W[6], data, 24);
	GET_UINT32_BE (W[7], data, 28);
	GET_UINT32_BE (W[8], data, 32);
	GET_UINT32_BE (W[9], data, 36);
	GET_UINT32_BE (W[10], data, 40);
	GET_UINT32_BE (W[11], data, 44);
	GET_UINT32_BE (W[12], data, 48);
	GET_UINT32_BE (W[13], data, 52);
	GET_UINT32_BE (W[14], data, 56);
	GET_UINT32_BE (W[15], data, 60);

#define S(x,n)	((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))

#define R(t) (						\
	temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^	\
	       W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],	\
	( W[t & 0x0F] = S(temp,1) )			\
)

#define P(a,b,c,d,e,x)	{				\
	e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);	\
}

	A = ctx->state[0];
	B = ctx->state[1];
	C = ctx->state[2];
	D = ctx->state[3];
	E = ctx->state[4];

#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999

	P (A, B, C, D, E, W[0]);
	P (E, A, B, C, D, W[1]);
	P (D, E, A, B, C, W[2]);
	P (C, D, E, A, B, W[3]);
	P (B, C, D, E, A, W[4]);
	P (A, B, C, D, E, W[5]);
	P (E, A, B, C, D, W[6]);
	P (D, E, A, B, C, W[7]);
	P (C, D, E, A, B, W[8]);
	P (B, C, D, E, A, W[9]);
	P (A, B, C, D, E, W[10]);
	P (E, A, B, C, D, W[11]);
	P (D, E, A, B, C, W[12]);
	P (C, D, E, A, B, W[13]);
	P (B, C, D, E, A, W[14]);
	P (A, B, C, D, E, W[15]);
	P (E, A, B, C, D, R (16));
	P (D, E, A, B, C, R (17));
	P (C, D, E, A, B, R (18));
	P (B, C, D, E, A, R (19));

#undef K
#undef F

#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1

	P (A, B, C, D, E, R (20));
	P (E, A, B, C, D, R (21));
	P (D, E, A, B, C, R (22));
	P (C, D, E, A, B, R (23));
	P (B, C, D, E, A, R (24));
	P (A, B, C, D, E, R (25));
	P (E, A, B, C, D, R (26));
	P (D, E, A, B, C, R (27));
	P (C, D, E, A, B, R (28));
	P (B, C, D, E, A, R (29));
	P (A, B, C, D, E, R (30));
	P (E, A, B, C, D, R (31));
	P (D, E, A, B, C, R (32));
	P (C, D, E, A, B, R (33));
	P (B, C, D, E, A, R (34));
	P (A, B, C, D, E, R (35));
	P (E, A, B, C, D, R (36));
	P (D, E, A, B, C, R (37));
	P (C, D, E, A, B, R (38));
	P (B, C, D, E, A, R (39));

#undef K
#undef F

#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC

	P (A, B, C, D, E, R (40));
	P (E, A, B, C, D, R (41));
	P (D, E, A, B, C, R (42));
	P (C, D, E, A, B, R (43));
	P (B, C, D, E, A, R (44));
	P (A, B, C, D, E, R (45));
	P (E, A, B, C, D, R (46));
	P (D, E, A, B, C, R (47));
	P (C, D, E, A, B, R (48));
	P (B, C, D, E, A, R (49));
	P (A, B, C, D, E, R (50));
	P (E, A, B, C, D, R (51));
	P (D, E, A, B, C, R (52));
	P (C, D, E, A, B, R (53));
	P (B, C, D, E, A, R (54));
	P (A, B, C, D, E, R (55));
	P (E, A, B, C, D, R (56));
	P (D, E, A, B, C, R (57));
	P (C, D, E, A, B, R (58));
	P (B, C, D, E, A, R (59));

#undef K
#undef F

#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6

	P (A, B, C, D, E, R (60));
	P (E, A, B, C, D, R (61));
	P (D, E, A, B, C, R (62));
	P (C, D, E, A, B, R (63));
	P (B, C, D, E, A, R (64));
	P (A, B, C, D, E, R (65));
	P (E, A, B, C, D, R (66));
	P (D, E, A, B, C, R (67));
	P (C, D, E, A, B, R (68));
	P (B, C, D, E, A, R (69));
	P (A, B, C, D, E, R (70));
	P (E, A, B, C, D, R (71));
	P (D, E, A, B, C, R (72));
	P (C, D, E, A, B, R (73));
	P (B, C, D, E, A, R (74));
	P (A, B, C, D, E, R (75));
	P (E, A, B, C, D, R (76));
	P (D, E, A, B, C, R (77));
	P (C, D, E, A, B, R (78));
	P (B, C, D, E, A, R (79));

#undef K
#undef F

	ctx->state[0] += A;
	ctx->state[1] += B;
	ctx->state[2] += C;
	ctx->state[3] += D;
	ctx->state[4] += E;
}

#undef P
#undef R
#undef S

/*
 * SHA-1 process buffer
 */
static
void sha1_update(sha1_context *ctx, const unsigned char *input,
		 unsigned int ilen)
{
	int fill;
	unsigned long left;

	if (ilen <= 0)
		return;

	left = ctx->total[0] & 0x3F;
	fill = 64 - left;

	ctx->total[0] += ilen;
	ctx->total[0] &= 0xFFFFFFFF;

	if (ctx->total[0] < (unsigned long) ilen)
		ctx->total[1]++;

	if (left && ilen >= fill) {
		memcpy ((void *) (ctx->buffer + left), (void *) input, fill);
		sha1_process (ctx, ctx->buffer);
		input += fill;
		ilen -= fill;
		left = 0;
	}

	while (ilen >= 64) {
		sha1_process (ctx, input);
		input += 64;
		ilen -= 64;
	}

	if (ilen > 0) {
		memcpy ((void *) (ctx->buffer + left), (void *) input, ilen);
	}
}

static const unsigned char sha1_padding[64] = {
	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/*
 * SHA-1 final digest
 */
static
void sha1_finish (sha1_context * ctx, unsigned char output[20])
{
	unsigned long last, padn;
	unsigned long high, low;
	unsigned char msglen[8];

	high = (ctx->total[0] >> 29)
		| (ctx->total[1] << 3);
	low = (ctx->total[0] << 3);

	PUT_UINT32_BE (high, msglen, 0);
	PUT_UINT32_BE (low, msglen, 4);

	last = ctx->total[0] & 0x3F;
	padn = (last < 56) ? (56 - last) : (120 - last);

	sha1_update (ctx, (unsigned char *) sha1_padding, padn);
	sha1_update (ctx, msglen, 8);

	PUT_UINT32_BE (ctx->state[0], output, 0);
	PUT_UINT32_BE (ctx->state[1], output, 4);
	PUT_UINT32_BE (ctx->state[2], output, 8);
	PUT_UINT32_BE (ctx->state[3], output, 12);
	PUT_UINT32_BE (ctx->state[4], output, 16);
}

/*
 * Output = SHA-1( input buffer )
 */
static
void sha1_csum(const unsigned char *input, unsigned int ilen,
	       unsigned char *output)
{
	sha1_context ctx;

	sha1_starts (&ctx);
	sha1_update (&ctx, input, ilen);
	sha1_finish (&ctx, output);
}

typedef struct {
	uint32_t total[2];
	uint32_t state[8];
	uint8_t buffer[64];
} sha256_context;

static
void sha256_starts(sha256_context * ctx)
{
	ctx->total[0] = 0;
	ctx->total[1] = 0;

	ctx->state[0] = 0x6A09E667;
	ctx->state[1] = 0xBB67AE85;
	ctx->state[2] = 0x3C6EF372;
	ctx->state[3] = 0xA54FF53A;
	ctx->state[4] = 0x510E527F;
	ctx->state[5] = 0x9B05688C;
	ctx->state[6] = 0x1F83D9AB;
	ctx->state[7] = 0x5BE0CD19;
}

static void sha256_process(sha256_context *ctx, const uint8_t data[64])
{
	uint32_t temp1, temp2;
	uint32_t W[64];
	uint32_t A, B, C, D, E, F, G, H;

	GET_UINT32_BE(W[0], data, 0);
	GET_UINT32_BE(W[1], data, 4);
	GET_UINT32_BE(W[2], data, 8);
	GET_UINT32_BE(W[3], data, 12);
	GET_UINT32_BE(W[4], data, 16);
	GET_UINT32_BE(W[5], data, 20);
	GET_UINT32_BE(W[6], data, 24);
	GET_UINT32_BE(W[7], data, 28);
	GET_UINT32_BE(W[8], data, 32);
	GET_UINT32_BE(W[9], data, 36);
	GET_UINT32_BE(W[10], data, 40);
	GET_UINT32_BE(W[11], data, 44);
	GET_UINT32_BE(W[12], data, 48);
	GET_UINT32_BE(W[13], data, 52);
	GET_UINT32_BE(W[14], data, 56);
	GET_UINT32_BE(W[15], data, 60);

#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))

#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))

#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))

#define F0(x,y,z) ((x & y) | (z & (x | y)))
#define F1(x,y,z) (z ^ (x & (y ^ z)))

#define R(t)					\
(						\
	W[t] = S1(W[t - 2]) + W[t - 7] +	\
		S0(W[t - 15]) + W[t - 16]	\
)

#define P(a,b,c,d,e,f,g,h,x,K) {		\
	temp1 = h + S3(e) + F1(e,f,g) + K + x;	\
	temp2 = S2(a) + F0(a,b,c);		\
	d += temp1; h = temp1 + temp2;		\
}

	A = ctx->state[0];
	B = ctx->state[1];
	C = ctx->state[2];
	D = ctx->state[3];
	E = ctx->state[4];
	F = ctx->state[5];
	G = ctx->state[6];
	H = ctx->state[7];

	P(A, B, C, D, E, F, G, H, W[0], 0x428A2F98);
	P(H, A, B, C, D, E, F, G, W[1], 0x71374491);
	P(G, H, A, B, C, D, E, F, W[2], 0xB5C0FBCF);
	P(F, G, H, A, B, C, D, E, W[3], 0xE9B5DBA5);
	P(E, F, G, H, A, B, C, D, W[4], 0x3956C25B);
	P(D, E, F, G, H, A, B, C, W[5], 0x59F111F1);
	P(C, D, E, F, G, H, A, B, W[6], 0x923F82A4);
	P(B, C, D, E, F, G, H, A, W[7], 0xAB1C5ED5);
	P(A, B, C, D, E, F, G, H, W[8], 0xD807AA98);
	P(H, A, B, C, D, E, F, G, W[9], 0x12835B01);
	P(G, H, A, B, C, D, E, F, W[10], 0x243185BE);
	P(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
	P(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
	P(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
	P(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
	P(B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
	P(A, B, C, D, E, F, G, H, R(16), 0xE49B69C1);
	P(H, A, B, C, D, E, F, G, R(17), 0xEFBE4786);
	P(G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6);
	P(F, G, H, A, B, C, D, E, R(19), 0x240CA1CC);
	P(E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F);
	P(D, E, F, G, H, A, B, C, R(21), 0x4A7484AA);
	P(C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC);
	P(B, C, D, E, F, G, H, A, R(23), 0x76F988DA);
	P(A, B, C, D, E, F, G, H, R(24), 0x983E5152);
	P(H, A, B, C, D, E, F, G, R(25), 0xA831C66D);
	P(G, H, A, B, C, D, E, F, R(26), 0xB00327C8);
	P(F, G, H, A, B, C, D, E, R(27), 0xBF597FC7);
	P(E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3);
	P(D, E, F, G, H, A, B, C, R(29), 0xD5A79147);
	P(C, D, E, F, G, H, A, B, R(30), 0x06CA6351);
	P(B, C, D, E, F, G, H, A, R(31), 0x14292967);
	P(A, B, C, D, E, F, G, H, R(32), 0x27B70A85);
	P(H, A, B, C, D, E, F, G, R(33), 0x2E1B2138);
	P(G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC);
	P(F, G, H, A, B, C, D, E, R(35), 0x53380D13);
	P(E, F, G, H, A, B, C, D, R(36), 0x650A7354);
	P(D, E, F, G, H, A, B, C, R(37), 0x766A0ABB);
	P(C, D, E, F, G, H, A, B, R(38), 0x81C2C92E);
	P(B, C, D, E, F, G, H, A, R(39), 0x92722C85);
	P(A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1);
	P(H, A, B, C, D, E, F, G, R(41), 0xA81A664B);
	P(G, H, A, B, C, D, E, F, R(42), 0xC24B8B70);
	P(F, G, H, A, B, C, D, E, R(43), 0xC76C51A3);
	P(E, F, G, H, A, B, C, D, R(44), 0xD192E819);
	P(D, E, F, G, H, A, B, C, R(45), 0xD6990624);
	P(C, D, E, F, G, H, A, B, R(46), 0xF40E3585);
	P(B, C, D, E, F, G, H, A, R(47), 0x106AA070);
	P(A, B, C, D, E, F, G, H, R(48), 0x19A4C116);
	P(H, A, B, C, D, E, F, G, R(49), 0x1E376C08);
	P(G, H, A, B, C, D, E, F, R(50), 0x2748774C);
	P(F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5);
	P(E, F, G, H, A, B, C, D, R(52), 0x391C0CB3);
	P(D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A);
	P(C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F);
	P(B, C, D, E, F, G, H, A, R(55), 0x682E6FF3);
	P(A, B, C, D, E, F, G, H, R(56), 0x748F82EE);
	P(H, A, B, C, D, E, F, G, R(57), 0x78A5636F);
	P(G, H, A, B, C, D, E, F, R(58), 0x84C87814);
	P(F, G, H, A, B, C, D, E, R(59), 0x8CC70208);
	P(E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA);
	P(D, E, F, G, H, A, B, C, R(61), 0xA4506CEB);
	P(C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7);
	P(B, C, D, E, F, G, H, A, R(63), 0xC67178F2);

	ctx->state[0] += A;
	ctx->state[1] += B;
	ctx->state[2] += C;
	ctx->state[3] += D;
	ctx->state[4] += E;
	ctx->state[5] += F;
	ctx->state[6] += G;
	ctx->state[7] += H;
}

#undef P
#undef R
#undef F1
#undef F0
#undef S3
#undef S2
#undef S1
#undef S0
#undef ROTR
#undef SHR

static
void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length)
{
	uint32_t left, fill;

	if (!length)
		return;

	left = ctx->total[0] & 0x3F;
	fill = 64 - left;

	ctx->total[0] += length;
	ctx->total[0] &= 0xFFFFFFFF;

	if (ctx->total[0] < length)
		ctx->total[1]++;

	if (left && length >= fill) {
		memcpy((void *) (ctx->buffer + left), (void *) input, fill);
		sha256_process(ctx, ctx->buffer);
		length -= fill;
		input += fill;
		left = 0;
	}

	while (length >= 64) {
		sha256_process(ctx, input);
		length -= 64;
		input += 64;
	}

	if (length)
		memcpy((void *) (ctx->buffer + left), (void *) input, length);
}

static uint8_t sha256_padding[64] = {
	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

static
void sha256_finish(sha256_context * ctx, uint8_t digest[32])
{
	uint32_t last, padn;
	uint32_t high, low;
	uint8_t msglen[8];

	high = ((ctx->total[0] >> 29)
		| (ctx->total[1] << 3));
	low = (ctx->total[0] << 3);

	PUT_UINT32_BE(high, msglen, 0);
	PUT_UINT32_BE(low, msglen, 4);

	last = ctx->total[0] & 0x3F;
	padn = (last < 56) ? (56 - last) : (120 - last);

	sha256_update(ctx, sha256_padding, padn);
	sha256_update(ctx, msglen, 8);

	PUT_UINT32_BE(ctx->state[0], digest, 0);
	PUT_UINT32_BE(ctx->state[1], digest, 4);
	PUT_UINT32_BE(ctx->state[2], digest, 8);
	PUT_UINT32_BE(ctx->state[3], digest, 12);
	PUT_UINT32_BE(ctx->state[4], digest, 16);
	PUT_UINT32_BE(ctx->state[5], digest, 20);
	PUT_UINT32_BE(ctx->state[6], digest, 24);
	PUT_UINT32_BE(ctx->state[7], digest, 28);
}

/*
 * Output = SHA-256( input buffer ).
 */
static
void sha256_csum(const unsigned char *input, unsigned int ilen,
		 unsigned char *output)
{
	sha256_context ctx;

	sha256_starts(&ctx);
	sha256_update(&ctx, input, ilen);
	sha256_finish(&ctx, output);
}

/* #define DEBUG */

static bool g_debug =
#ifdef DEBUG
        true;
#else
        false;
#endif /* DEBUG */

#define LOGE(fmt, args...)                                                     \
  fprintf(stderr, "E/%s(%d): " fmt "\n", __func__, __LINE__, ##args)
#define LOGD(fmt, args...)                                                     \
  do {                                                                         \
    if (g_debug)                                                               \
      fprintf(stderr, "D/%s(%d): " fmt "\n", __func__, __LINE__, ##args);      \
  } while (0)

/* sync with ./board/rockchip/rk30xx/rkloader.c #define FDT_PATH */
#define FDT_PATH "rk-kernel.dtb"
#define DTD_SUBFIX ".dtb"

#define DEFAULT_IMAGE_PATH "resource.img"
#define DEFAULT_UNPACK_DIR "out"
#define BLOCK_SIZE 512

#define RESOURCE_PTN_HDR_SIZE 1
#define INDEX_TBL_ENTR_SIZE 1

#define RESOURCE_PTN_VERSION 0
#define INDEX_TBL_VERSION 0

#define RESOURCE_PTN_HDR_MAGIC "RSCE"
typedef struct {
	char magic[4]; /* tag, "RSCE" */
	uint16_t resource_ptn_version;
	uint16_t index_tbl_version;
	uint8_t header_size;    /* blocks, size of ptn header. */
	uint8_t tbl_offset;     /* blocks, offset of index table. */
	uint8_t tbl_entry_size; /* blocks, size of index table's entry. */
	uint32_t tbl_entry_num; /* numbers of index table's entry. */
} resource_ptn_header;

#define INDEX_TBL_ENTR_TAG "ENTR"
#define MAX_INDEX_ENTRY_PATH_LEN	220
#define MAX_HASH_LEN			32

typedef struct {
	char tag[4]; /* tag, "ENTR" */
	char path[MAX_INDEX_ENTRY_PATH_LEN];
	char hash[MAX_HASH_LEN]; /* hash data */
	uint32_t hash_size;	 /* 20 or 32 */
	uint32_t content_offset; /* blocks, offset of resource content. */
	uint32_t content_size;   /* bytes, size of resource content. */
} index_tbl_entry;

#define OPT_VERBOSE "--verbose"
#define OPT_HELP "--help"
#define OPT_VERSION "--version"
#define OPT_PRINT "--print"
#define OPT_PACK "--pack"
#define OPT_UNPACK "--unpack"
#define OPT_TEST_LOAD "--test_load"
#define OPT_TEST_CHARGE "--test_charge"
#define OPT_IMAGE "--image="
#define OPT_ROOT "--root="

#define VERSION "2014-5-31 14:43:42"

typedef struct {
	char path[MAX_INDEX_ENTRY_PATH_LEN];
	uint32_t content_offset; /* blocks, offset of resource content. */
	uint32_t content_size;   /* bytes, size of resource content. */
	void *load_addr;
} resource_content;

typedef struct {
	int max_level;
	int num;
	int delay;
	char prefix[MAX_INDEX_ENTRY_PATH_LEN];
} anim_level_conf;

#define DEF_CHARGE_DESC_PATH "charge_anim_desc.txt"

#define OPT_CHARGE_ANIM_DELAY "delay="
#define OPT_CHARGE_ANIM_LOOP_CUR "only_current_level="
#define OPT_CHARGE_ANIM_LEVELS "levels="
#define OPT_CHARGE_ANIM_LEVEL_CONF "max_level="
#define OPT_CHARGE_ANIM_LEVEL_NUM "num="
#define OPT_CHARGE_ANIM_LEVEL_PFX "prefix="

static char image_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0";

static int fix_blocks(size_t size)
{
	return (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
}

static const char *fix_path(const char *path)
{
	if (!memcmp(path, "./", 2)) {
		return path + 2;
	}
	return path;
}

static uint16_t switch_short(uint16_t x)
{
	uint16_t val;
	uint8_t *p = (uint8_t *)(&x);

	val = (*p++ & 0xff) << 0;
	val |= (*p & 0xff) << 8;

	return val;
}

static uint32_t switch_int(uint32_t x)
{
	uint32_t val;
	uint8_t *p = (uint8_t *)(&x);

	val = (*p++ & 0xff) << 0;
	val |= (*p++ & 0xff) << 8;
	val |= (*p++ & 0xff) << 16;
	val |= (*p & 0xff) << 24;

	return val;
}

static void fix_header(resource_ptn_header *header)
{
	/* switch for be. */
	header->resource_ptn_version = switch_short(header->resource_ptn_version);
	header->index_tbl_version = switch_short(header->index_tbl_version);
	header->tbl_entry_num = switch_int(header->tbl_entry_num);
}

static void fix_entry(index_tbl_entry *entry)
{
	/* switch for be. */
	entry->content_offset = switch_int(entry->content_offset);
	entry->content_size = switch_int(entry->content_size);
}

static int inline get_ptn_offset(void)
{
	return 0;
}

static bool StorageWriteLba(int offset_block, void *data, int blocks)
{
	bool ret = false;
	FILE *file = fopen(image_path, "rb+");
	if (!file)
		goto end;
	int offset = offset_block * BLOCK_SIZE;
	fseek(file, offset, SEEK_SET);
	if (offset != ftell(file)) {
		LOGE("Failed to seek %s to %d!", image_path, offset);
		goto end;
	}
	if (!fwrite(data, blocks * BLOCK_SIZE, 1, file)) {
		LOGE("Failed to write %s!", image_path);
		goto end;
	}
	ret = true;
end:
	if (file)
		fclose(file);
	return ret;
}

static bool StorageReadLba(int offset_block, void *data, int blocks)
{
	bool ret = false;
	FILE *file = fopen(image_path, "rb");
	if (!file)
		goto end;
	int offset = offset_block * BLOCK_SIZE;
	fseek(file, offset, SEEK_SET);
	if (offset != ftell(file)) {
		goto end;
	}
	if (!fread(data, blocks * BLOCK_SIZE, 1, file)) {
		goto end;
	}
	ret = true;
end:
	if (file)
		fclose(file);
	return ret;
}

static bool write_data(int offset_block, void *data, size_t len)
{
	bool ret = false;
	if (!data)
		goto end;
	int blocks = len / BLOCK_SIZE;
	if (blocks && !StorageWriteLba(offset_block, data, blocks)) {
		goto end;
	}
	int left = len % BLOCK_SIZE;
	if (left) {
		char buf[BLOCK_SIZE] = "\0";
		memcpy(buf, data + blocks * BLOCK_SIZE, left);
		if (!StorageWriteLba(offset_block + blocks, buf, 1))
			goto end;
	}
	ret = true;
end:
	return ret;
}

/**********************load test************************/
static int load_file(const char *file_path, int offset_block, int blocks);

static int test_load(int argc, char **argv)
{
	if (argc < 1) {
		LOGE("Nothing to load!");
		return -1;
	}
	const char *file_path;
	int offset_block = 0;
	int blocks = 0;
	if (argc > 0) {
		file_path = (const char *)fix_path(argv[0]);
		argc--, argv++;
	}
	if (argc > 0) {
		offset_block = atoi(argv[0]);
		argc--, argv++;
	}
	if (argc > 0) {
		blocks = atoi(argv[0]);
	}
	return load_file(file_path, offset_block, blocks);
}

static void free_content(resource_content *content)
{
	if (content->load_addr) {
		free(content->load_addr);
		content->load_addr = 0;
	}
}

static void tests_dump_file(const char *path, void *data, int len)
{
	FILE *file = fopen(path, "wb");
	if (!file)
		return;
	fwrite(data, len, 1, file);
	fclose(file);
}

static bool load_content(resource_content *content)
{
	if (content->load_addr)
		return true;
	int blocks = fix_blocks(content->content_size);
	content->load_addr = malloc(blocks * BLOCK_SIZE);
	if (!content->load_addr)
		return false;
	if (!StorageReadLba(get_ptn_offset() + content->content_offset,
	                    content->load_addr, blocks)) {
		free_content(content);
		return false;
	}

	tests_dump_file(content->path, content->load_addr, content->content_size);
	return true;
}

static bool load_content_data(resource_content *content, int offset_block,
                              void *data, int blocks)
{
	if (!StorageReadLba(get_ptn_offset() + content->content_offset + offset_block,
	                    data, blocks)) {
		return false;
	}
	tests_dump_file(content->path, data, blocks * BLOCK_SIZE);
	return true;
}

static bool get_entry(const char *file_path, index_tbl_entry *entry)
{
	bool ret = false;
	char buf[BLOCK_SIZE];
	resource_ptn_header header;
	if (!StorageReadLba(get_ptn_offset(), buf, 1)) {
		LOGE("Failed to read header!");
		goto end;
	}
	memcpy(&header, buf, sizeof(header));

	if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) {
		LOGE("Not a resource image(%s)!", image_path);
		goto end;
	}
	/* test on pc, switch for be. */
	fix_header(&header);

	/* TODO: support header_size & tbl_entry_size */
	if (header.resource_ptn_version != RESOURCE_PTN_VERSION ||
	    header.header_size != RESOURCE_PTN_HDR_SIZE ||
	    header.index_tbl_version != INDEX_TBL_VERSION ||
	    header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) {
		LOGE("Not supported in this version!");
		goto end;
	}

	int i;
	for (i = 0; i < header.tbl_entry_num; i++) {
		/* TODO: support tbl_entry_size */
		if (!StorageReadLba(
		            get_ptn_offset() + header.header_size + i * header.tbl_entry_size,
		            buf, 1)) {
			LOGE("Failed to read index entry:%d!", i);
			goto end;
		}
		memcpy(entry, buf, sizeof(*entry));

		if (memcmp(entry->tag, INDEX_TBL_ENTR_TAG, sizeof(entry->tag))) {
			LOGE("Something wrong with index entry:%d!", i);
			goto end;
		}

		if (!strncmp(entry->path, file_path, sizeof(entry->path)))
			break;
	}
	if (i == header.tbl_entry_num) {
		LOGE("Cannot find %s!", file_path);
		goto end;
	}
	/* test on pc, switch for be. */
	fix_entry(entry);

	printf("Found entry:\n\tpath:%s\n\toffset:%d\tsize:%d\n", entry->path,
	       entry->content_offset, entry->content_size);

	ret = true;
end:
	return ret;
}

static bool get_content(resource_content *content)
{
	bool ret = false;
	index_tbl_entry entry;
	if (!get_entry(content->path, &entry))
		goto end;
	content->content_offset = entry.content_offset;
	content->content_size = entry.content_size;
	ret = true;
end:
	return ret;
}

static int load_file(const char *file_path, int offset_block, int blocks)
{
	printf("Try to load:%s", file_path);
	if (blocks) {
		printf(", offset block:%d, blocks:%d\n", offset_block, blocks);
	} else {
		printf("\n");
	}
	bool ret = false;
	resource_content content;
	snprintf(content.path, sizeof(content.path), "%s", file_path);
	content.load_addr = 0;
	if (!get_content(&content)) {
		goto end;
	}
	if (!blocks) {
		if (!load_content(&content)) {
			goto end;
		}
	} else {
		void *data = malloc(blocks * BLOCK_SIZE);
		if (!data)
			goto end;
		if (!load_content_data(&content, offset_block, data, blocks)) {
			goto end;
		}
	}
	ret = true;
end:
	free_content(&content);
	return ret;
}

/**********************load test end************************/
/**********************anim test************************/

static bool parse_level_conf(const char *arg, anim_level_conf *level_conf)
{
	memset(level_conf, 0, sizeof(anim_level_conf));
	char *buf = NULL;
	buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_CONF);
	if (buf) {
		level_conf->max_level = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_CONF));
	} else {
		LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_CONF);
		return false;
	}
	buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_NUM);
	if (buf) {
		level_conf->num = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_NUM));
		if (level_conf->num <= 0) {
			return false;
		}
	} else {
		LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_NUM);
		return false;
	}
	buf = strstr(arg, OPT_CHARGE_ANIM_DELAY);
	if (buf) {
		level_conf->delay = atoi(buf + strlen(OPT_CHARGE_ANIM_DELAY));
	}
	buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_PFX);
	if (buf) {
		snprintf(level_conf->prefix, sizeof(level_conf->prefix), "%s",
		         buf + strlen(OPT_CHARGE_ANIM_LEVEL_PFX));
	} else {
		LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_PFX);
		return false;
	}

	LOGD("Found conf:\nmax_level:%d, num:%d, delay:%d, prefix:%s",
	     level_conf->max_level, level_conf->num, level_conf->delay,
	     level_conf->prefix);
	return true;
}

static int test_charge(int argc, char **argv)
{
	const char *desc;
	if (argc > 0) {
		desc = argv[0];
	} else {
		desc = DEF_CHARGE_DESC_PATH;
	}

	resource_content content;
	snprintf(content.path, sizeof(content.path), "%s", desc);
	content.load_addr = 0;
	if (!get_content(&content)) {
		goto end;
	}
	if (!load_content(&content)) {
		goto end;
	}

	char *buf = (char *)content.load_addr;
	char *end = buf + content.content_size - 1;
	*end = '\0';
	LOGD("desc:\n%s", buf);

	int pos = 0;
	while (1) {
		char *line = (char *)memchr(buf + pos, '\n', strlen(buf + pos));
		if (!line)
			break;
		*line = '\0';
		LOGD("splite:%s", buf + pos);
		pos += (strlen(buf + pos) + 1);
	}

	int delay = 900;
	int only_current_level = false;
	anim_level_conf *level_confs = NULL;
	int level_conf_pos = 0;
	int level_conf_num = 0;

	while (true) {
		if (buf >= end)
			break;
		const char *arg = buf;
		buf += (strlen(buf) + 1);

		LOGD("parse arg:%s", arg);
		if (!memcmp(arg, OPT_CHARGE_ANIM_LEVEL_CONF,
		            strlen(OPT_CHARGE_ANIM_LEVEL_CONF))) {
			if (!level_confs) {
				LOGE("Found level conf before levels!");
				goto end;
			}
			if (level_conf_pos >= level_conf_num) {
				LOGE("Too many level confs!(%d >= %d)", level_conf_pos, level_conf_num);
				goto end;
			}
			if (!parse_level_conf(arg, level_confs + level_conf_pos)) {
				LOGE("Failed to parse level conf:%s", arg);
				goto end;
			}
			level_conf_pos++;
		} else if (!memcmp(arg, OPT_CHARGE_ANIM_DELAY,
		                   strlen(OPT_CHARGE_ANIM_DELAY))) {
			delay = atoi(arg + strlen(OPT_CHARGE_ANIM_DELAY));
			LOGD("Found delay:%d", delay);
		} else if (!memcmp(arg, OPT_CHARGE_ANIM_LOOP_CUR,
		                   strlen(OPT_CHARGE_ANIM_LOOP_CUR))) {
			only_current_level =
			        !memcmp(arg + strlen(OPT_CHARGE_ANIM_LOOP_CUR), "true", 4);
			LOGD("Found only_current_level:%d", only_current_level);
		} else if (!memcmp(arg, OPT_CHARGE_ANIM_LEVELS,
		                   strlen(OPT_CHARGE_ANIM_LEVELS))) {
			if (level_conf_num) {
				goto end;
			}
			level_conf_num = atoi(arg + strlen(OPT_CHARGE_ANIM_LEVELS));
			if (!level_conf_num) {
				goto end;
			}
			level_confs =
			        (anim_level_conf *)malloc(level_conf_num * sizeof(anim_level_conf));
			LOGD("Found levels:%d", level_conf_num);
		} else {
			LOGE("Unknown arg:%s", arg);
			goto end;
		}
	}

	if (level_conf_pos != level_conf_num || !level_conf_num) {
		LOGE("Something wrong with level confs!");
		goto end;
	}

	int i = 0, j = 0;
	for (i = 0; i < level_conf_num; i++) {
		if (!level_confs[i].delay) {
			level_confs[i].delay = delay;
		}
		if (!level_confs[i].delay) {
			LOGE("Missing delay in level conf:%d", i);
			goto end;
		}
		for (j = 0; j < i; j++) {
			if (level_confs[j].max_level == level_confs[i].max_level) {
				LOGE("Dup level conf:%d", i);
				goto end;
			}
			if (level_confs[j].max_level > level_confs[i].max_level) {
				anim_level_conf conf = level_confs[i];
				memmove(level_confs + j + 1, level_confs + j,
				        (i - j) * sizeof(anim_level_conf));
				level_confs[j] = conf;
			}
		}
	}

	printf("Parse anim desc(%s):\n", desc);
	printf("only_current_level=%d\n", only_current_level);
	printf("level conf:\n");
	for (i = 0; i < level_conf_num; i++) {
		printf("\tmax=%d, delay=%d, num=%d, prefix=%s\n", level_confs[i].max_level,
		       level_confs[i].delay, level_confs[i].num, level_confs[i].prefix);
	}

end:
	free_content(&content);
	return 0;
}

/**********************anim test end************************/
/**********************append file************************/

static const char *PROG = NULL;
static resource_ptn_header header;
static bool just_print = false;
static char root_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0";

static void version(void)
{
	printf("%s (cjf@rock-chips.com)\t" VERSION "\n", PROG);
}

static void usage(void)
{
	printf("Usage: %s [options] [FILES]\n", PROG);
	printf("Tools for Rockchip's resource image.\n");
	version();
	printf("Options:\n");
	printf("\t" OPT_PACK "\t\t\tPack image from given files.\n");
	printf("\t" OPT_UNPACK "\t\tUnpack given image to current dir.\n");
	printf("\t" OPT_IMAGE "path"
	       "\t\tSpecify input/output image path.\n");
	printf("\t" OPT_PRINT "\t\t\tJust print informations.\n");
	printf("\t" OPT_VERBOSE "\t\tDisplay more runtime informations.\n");
	printf("\t" OPT_HELP "\t\t\tDisplay this information.\n");
	printf("\t" OPT_VERSION "\t\tDisplay version information.\n");
	printf("\t" OPT_ROOT "path"
	       "\t\tSpecify resources' root dir.\n");
}

static int pack_image(int file_num, const char **files);
static int unpack_image(const char *unpack_dir);

enum ACTION {
	ACTION_PACK,
	ACTION_UNPACK,
	ACTION_TEST_LOAD,
	ACTION_TEST_CHARGE,
};

int main(int argc, char **argv)
{
	PROG = fix_path(argv[0]);

	enum ACTION action = ACTION_PACK;

	argc--, argv++;
	while (argc > 0 && argv[0][0] == '-') {
		/* it's a opt arg. */
		const char *arg = argv[0];
		argc--, argv++;
		if (!strcmp(OPT_VERBOSE, arg)) {
			g_debug = true;
		} else if (!strcmp(OPT_HELP, arg)) {
			usage();
			return 0;
		} else if (!strcmp(OPT_VERSION, arg)) {
			version();
			return 0;
		} else if (!strcmp(OPT_PRINT, arg)) {
			just_print = true;
		} else if (!strcmp(OPT_PACK, arg)) {
			action = ACTION_PACK;
		} else if (!strcmp(OPT_UNPACK, arg)) {
			action = ACTION_UNPACK;
		} else if (!strcmp(OPT_TEST_LOAD, arg)) {
			action = ACTION_TEST_LOAD;
		} else if (!strcmp(OPT_TEST_CHARGE, arg)) {
			action = ACTION_TEST_CHARGE;
		} else if (!memcmp(OPT_IMAGE, arg, strlen(OPT_IMAGE))) {
			snprintf(image_path, sizeof(image_path), "%s", arg + strlen(OPT_IMAGE));
		} else if (!memcmp(OPT_ROOT, arg, strlen(OPT_ROOT))) {
			snprintf(root_path, sizeof(root_path), "%s", arg + strlen(OPT_ROOT));
		} else {
			LOGE("Unknown opt:%s", arg);
			usage();
			return -1;
		}
	}

	if (!image_path[0]) {
		snprintf(image_path, sizeof(image_path), "%s", DEFAULT_IMAGE_PATH);
	}

	switch (action) {
	case ACTION_PACK: {
		int file_num = argc;
		const char **files = (const char **)argv;
		if (!file_num) {
			LOGE("No file to pack!");
			return 0;
		}
		LOGD("try to pack %d files.", file_num);
		return pack_image(file_num, files);
	}
	case ACTION_UNPACK: {
		return unpack_image(argc > 0 ? argv[0] : DEFAULT_UNPACK_DIR);
	}
	case ACTION_TEST_LOAD: {
		return test_load(argc, argv);
	}
	case ACTION_TEST_CHARGE: {
		return test_charge(argc, argv);
	}
	}
	/* not reach here. */
	return -1;
}

/************unpack code****************/
static bool mkdirs(char *path)
{
	char *tmp = path;
	char *pos = NULL;
	char buf[MAX_INDEX_ENTRY_PATH_LEN];
	bool ret = true;
	while ((pos = memchr(tmp, '/', strlen(tmp)))) {
		strcpy(buf, path);
		buf[pos - path] = '\0';
		tmp = pos + 1;
		LOGD("mkdir:%s", buf);
		if (!mkdir(buf, 0755)) {
			ret = false;
		}
	}
	if (!ret)
		LOGD("Failed to mkdir(%s)!", path);
	return ret;
}

static bool dump_file(FILE *file, const char *unpack_dir,
                      index_tbl_entry entry)
{
	LOGD("try to dump entry:%s", entry.path);
	bool ret = false;
	FILE *out_file = NULL;
	long int pos = 0;
	char path[MAX_INDEX_ENTRY_PATH_LEN * 2 + 1];
	if (just_print) {
		ret = true;
		goto done;
	}

	pos = ftell(file);
	snprintf(path, sizeof(path), "%s/%s", unpack_dir, entry.path);
	mkdirs(path);
	out_file = fopen(path, "wb");
	if (!out_file) {
		LOGE("Failed to create:%s", path);
		goto end;
	}
	long int offset = entry.content_offset * BLOCK_SIZE;
	fseek(file, offset, SEEK_SET);
	if (offset != ftell(file)) {
		LOGE("Failed to read content:%s", entry.path);
		goto end;
	}
	char buf[BLOCK_SIZE];
	int n;
	int len = entry.content_size;
	while (len > 0) {
		n = len > BLOCK_SIZE ? BLOCK_SIZE : len;
		if (!fread(buf, n, 1, file)) {
			LOGE("Failed to read content:%s", entry.path);
			goto end;
		}
		if (!fwrite(buf, n, 1, out_file)) {
			LOGE("Failed to write:%s", entry.path);
			goto end;
		}
		len -= n;
	}
done:
	ret = true;
end:
	if (out_file)
		fclose(out_file);
	if (pos)
		fseek(file, pos, SEEK_SET);
	return ret;
}

static int unpack_image(const char *dir)
{
	FILE *image_file = NULL;
	bool ret = false;
	char unpack_dir[MAX_INDEX_ENTRY_PATH_LEN];
	if (just_print)
		dir = ".";
	snprintf(unpack_dir, sizeof(unpack_dir), "%s", dir);
	if (!strlen(unpack_dir)) {
		goto end;
	} else if (unpack_dir[strlen(unpack_dir) - 1] == '/') {
		unpack_dir[strlen(unpack_dir) - 1] = '\0';
	}

	mkdir(unpack_dir, 0755);
	image_file = fopen(image_path, "rb");
	char buf[BLOCK_SIZE];
	if (!image_file) {
		LOGE("Failed to open:%s", image_path);
		goto end;
	}
	if (!fread(buf, BLOCK_SIZE, 1, image_file)) {
		LOGE("Failed to read header!");
		goto end;
	}
	memcpy(&header, buf, sizeof(header));

	if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) {
		LOGE("Not a resource image(%s)!", image_path);
		goto end;
	}
	/* switch for be. */
	fix_header(&header);

	printf("Dump header:\n");
	printf("partition version:%d.%d\n", header.resource_ptn_version,
	       header.index_tbl_version);
	printf("header size:%d\n", header.header_size);
	printf("index tbl:\n\toffset:%d\tentry size:%d\tentry num:%d\n",
	       header.tbl_offset, header.tbl_entry_size, header.tbl_entry_num);

	/* TODO: support header_size & tbl_entry_size */
	if (header.resource_ptn_version != RESOURCE_PTN_VERSION ||
	    header.header_size != RESOURCE_PTN_HDR_SIZE ||
	    header.index_tbl_version != INDEX_TBL_VERSION ||
	    header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) {
		LOGE("Not supported in this version!");
		goto end;
	}

	printf("Dump Index table:\n");
	index_tbl_entry entry;
	int i;
	for (i = 0; i < header.tbl_entry_num; i++) {
		/* TODO: support tbl_entry_size */
		if (!fread(buf, BLOCK_SIZE, 1, image_file)) {
			LOGE("Failed to read index entry:%d!", i);
			goto end;
		}
		memcpy(&entry, buf, sizeof(entry));

		if (memcmp(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag))) {
			LOGE("Something wrong with index entry:%d!", i);
			goto end;
		}
		/* switch for be. */
		fix_entry(&entry);

		printf("entry(%d):\n\tpath:%s\n\toffset:%d\tsize:%d\n", i, entry.path,
		       entry.content_offset, entry.content_size);
		if (!dump_file(image_file, unpack_dir, entry)) {
			goto end;
		}
	}
	printf("Unack %s to %s successed!\n", image_path, unpack_dir);
	ret = true;
end:
	if (image_file)
		fclose(image_file);
	return ret ? 0 : -1;
}

/************unpack code end****************/
/************pack code****************/

static inline size_t get_file_size(const char *path)
{
	LOGD("try to get size(%s)...", path);
	struct stat st;
	if (stat(path, &st) < 0) {
		LOGE("Failed to get size:%s", path);
		return -1;
	}
	LOGD("path:%s, size:%ld", path, st.st_size);
	return st.st_size;
}

static int write_file(int offset_block, const char *src_path,
		      char hash[], int hash_size)
{
	LOGD("try to write file(%s) to offset:%d...", src_path, offset_block);
	char *buf = NULL;
	int ret = -1;
	size_t file_size;
	FILE *src_file = fopen(src_path, "rb");
	if (!src_file) {
		LOGE("Failed to open:%s", src_path);
		goto end;
	}

	file_size = get_file_size(src_path);
	if (file_size < 0) {
		goto end;
	}

	buf = calloc(file_size, 1);
	if (!buf)
		goto end;

	if (!fread(buf, file_size, 1, src_file))
		goto end;

	if (!write_data(offset_block, buf, file_size))
		goto end;

	if (hash_size == 20)
		sha1_csum((const unsigned char *)buf, file_size,
			  (unsigned char *)hash);
	else if (hash_size == 32)
		sha256_csum((const unsigned char *)buf, file_size,
			    (unsigned char *)hash);
	else
		goto end;

	ret = file_size;
end:
	if (src_file)
		fclose(src_file);
	if (buf)
		free(buf);

	return ret;
}

static bool write_header(const int file_num)
{
	LOGD("try to write header...");
	memcpy(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic));
	header.resource_ptn_version = RESOURCE_PTN_VERSION;
	header.index_tbl_version = INDEX_TBL_VERSION;
	header.header_size = RESOURCE_PTN_HDR_SIZE;
	header.tbl_offset = header.header_size;
	header.tbl_entry_size = INDEX_TBL_ENTR_SIZE;
	header.tbl_entry_num = file_num;

	/* switch for le. */
	resource_ptn_header hdr = header;
	fix_header(&hdr);
	return write_data(0, &hdr, sizeof(hdr));
}

static bool write_index_tbl(const int file_num, const char **files)
{
	LOGD("try to write index table...");
	bool ret = false;
	bool foundFdt = false;
	int offset =
	        header.header_size + header.tbl_entry_size * header.tbl_entry_num;
	index_tbl_entry entry;
	char hash[20];	/* sha1 */
	int i;

	memcpy(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag));
	for (i = 0; i < file_num; i++) {
		size_t file_size = get_file_size(files[i]);
		if (file_size < 0)
			goto end;
		entry.content_size = file_size;
		entry.content_offset = offset;

		if (write_file(offset, files[i], hash, sizeof(hash)) < 0)
			goto end;

		memcpy(entry.hash, hash, sizeof(hash));
		entry.hash_size = sizeof(hash);

		LOGD("try to write index entry(%s)...", files[i]);

		/* switch for le. */
		fix_entry(&entry);
		memset(entry.path, 0, sizeof(entry.path));
		const char *path = files[i];
		if (root_path[0]) {
			if (!strncmp(path, root_path, strlen(root_path))) {
				path += strlen(root_path);
				if (path[0] == '/')
					path++;
			}
		}
		path = fix_path(path);
		if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) {
			if (!foundFdt) {
				/* use default path. */
				LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH);
				path = FDT_PATH;
				foundFdt = true;
			}
		}
		snprintf(entry.path, sizeof(entry.path), "%s", path);
		offset += fix_blocks(file_size);
		if (!write_data(header.header_size + i * header.tbl_entry_size, &entry,
		                sizeof(entry)))
			goto end;
	}
	ret = true;
end:
	return ret;
}

static int pack_image(int file_num, const char **files)
{
	bool ret = false;
	FILE *image_file = fopen(image_path, "wb");
	if (!image_file) {
		LOGE("Failed to create:%s", image_path);
		goto end;
	}
	fclose(image_file);

	/* prepare files */
	int i = 0;
	int pos = 0;
	const char *tmp;
	for (i = 0; i < file_num; i++) {
		if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) {
			/* dtb files for kernel. */
			tmp = files[pos];
			files[pos] = files[i];
			files[i] = tmp;
			pos++;
		} else if (!strcmp(fix_path(image_path), fix_path(files[i]))) {
			/* not to pack image itself! */
			tmp = files[file_num - 1];
			files[file_num - 1] = files[i];
			files[i] = tmp;
			file_num--;
		}
	}

	if (!write_header(file_num)) {
		LOGE("Failed to write header!");
		goto end;
	}
	if (!write_index_tbl(file_num, files)) {
		LOGE("Failed to write index table!");
		goto end;
	}
	printf("Pack to %s successed!\n", image_path);
	ret = true;
end:
	return ret ? 0 : -1;
}

/************pack code end****************/

2.修改 scripts/Makefile ,让他能够编译改c文件

hostprogs-always-$(CONFIG_ARCH_ROCKCHIP) += resource_tool

再次make,就没有错误了。

但是问题是,仍然没有生成boot.img

通过查看mkimg文件的流程,发现还缺少一个命令

解决:

从原来的sdk拷贝一个过来,再次make,就成功生成了boot.img。

mkbootimg是一个python脚本,内容如下:

python 复制代码
#!/usr/bin/env python
# Copyright 2015, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function

from argparse import ArgumentParser, FileType, Action
from hashlib import sha1
from os import fstat
import re
from struct import pack


BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096

def filesize(f):
    if f is None:
        return 0
    try:
        return fstat(f.fileno()).st_size
    except OSError:
        return 0


def update_sha(sha, f):
    if f:
        sha.update(f.read())
        f.seek(0)
        sha.update(pack('I', filesize(f)))
    else:
        sha.update(pack('I', 0))


def pad_file(f, padding):
    pad = (padding - (f.tell() & (padding - 1))) & (padding - 1)
    f.write(pack(str(pad) + 'x'))


def get_number_of_pages(image_size, page_size):
    """calculates the number of pages required for the image"""
    return (image_size + page_size - 1) / page_size


def get_recovery_dtbo_offset(args):
    """calculates the offset of recovery_dtbo image in the boot image"""
    num_header_pages = 1 # header occupies a page
    num_kernel_pages = get_number_of_pages(filesize(args.kernel), args.pagesize)
    num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk), args.pagesize)
    num_second_pages = get_number_of_pages(filesize(args.second), args.pagesize)
    dtbo_offset = args.pagesize * (num_header_pages + num_kernel_pages +
                                   num_ramdisk_pages + num_second_pages)
    return dtbo_offset


def write_header_v3(args):
    BOOT_IMAGE_HEADER_V3_SIZE = 1580
    BOOT_MAGIC = 'ANDROID!'.encode()

    args.output.write(pack('8s', BOOT_MAGIC))
    args.output.write(pack(
        '4I',
        filesize(args.kernel),                          # kernel size in bytes
        filesize(args.ramdisk),                         # ramdisk size in bytes
        (args.os_version << 11) | args.os_patch_level,  # os version and patch level
        BOOT_IMAGE_HEADER_V3_SIZE))

    args.output.write(pack('4I', 0, 0, 0, 0))           # reserved

    args.output.write(pack('I', args.header_version))   # version of bootimage header
    args.output.write(pack('1536s', args.cmdline.encode()))
    pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE)

def write_vendor_boot_header(args):
    VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
    BOOT_MAGIC = 'VNDRBOOT'.encode()

    args.vendor_boot.write(pack('8s', BOOT_MAGIC))
    args.vendor_boot.write(pack(
        '5I',
        args.header_version,                            # version of header
        args.pagesize,                                  # flash page size we assume
        args.base + args.kernel_offset,                 # kernel physical load addr
        args.base + args.ramdisk_offset,                # ramdisk physical load addr
        filesize(args.vendor_ramdisk)))                 # vendor ramdisk size in bytes
    args.vendor_boot.write(pack('2048s', args.vendor_cmdline.encode()))
    args.vendor_boot.write(pack('I', args.base + args.tags_offset)) # physical addr for kernel tags
    args.vendor_boot.write(pack('16s', args.board.encode())) # asciiz product name
    args.vendor_boot.write(pack('I', VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) # header size in bytes
    if filesize(args.dtb) == 0:
        raise ValueError("DTB image must not be empty.")
    args.vendor_boot.write(pack('I', filesize(args.dtb)))   # size in bytes
    args.vendor_boot.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
    pad_file(args.vendor_boot, args.pagesize)

def write_header(args):
    BOOT_IMAGE_HEADER_V1_SIZE = 1648
    BOOT_IMAGE_HEADER_V2_SIZE = 1660
    BOOT_MAGIC = 'ANDROID!'.encode()

    if args.header_version > 3:
        raise ValueError('Boot header version %d not supported' % args.header_version)
    elif args.header_version == 3:
        return write_header_v3(args)

    args.output.write(pack('8s', BOOT_MAGIC))
    final_ramdisk_offset = (args.base + args.ramdisk_offset) if filesize(args.ramdisk) > 0 else 0
    final_second_offset = (args.base + args.second_offset) if filesize(args.second) > 0 else 0
    args.output.write(pack(
        '10I',
        filesize(args.kernel),                          # size in bytes
        args.base + args.kernel_offset,                 # physical load addr
        filesize(args.ramdisk),                         # size in bytes
        final_ramdisk_offset,                           # physical load addr
        filesize(args.second),                          # size in bytes
        final_second_offset,                            # physical load addr
        args.base + args.tags_offset,                   # physical addr for kernel tags
        args.pagesize,                                  # flash page size we assume
        args.header_version,                            # version of bootimage header
        (args.os_version << 11) | args.os_patch_level)) # os version and patch level
    args.output.write(pack('16s', args.board.encode())) # asciiz product name
    args.output.write(pack('512s', args.cmdline[:512].encode()))

    sha = sha1()
    update_sha(sha, args.kernel)
    update_sha(sha, args.ramdisk)
    update_sha(sha, args.second)

    if args.header_version > 0:
        update_sha(sha, args.recovery_dtbo)
    if args.header_version > 1:
        update_sha(sha, args.dtb)

    img_id = pack('32s', sha.digest())

    args.output.write(img_id)
    args.output.write(pack('1024s', args.cmdline[512:].encode()))

    if args.header_version > 0:
        args.output.write(pack('I', filesize(args.recovery_dtbo)))   # size in bytes
        if args.recovery_dtbo:
            args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
        else:
            args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo

    # Populate boot image header size for header versions 1 and 2.
    if args.header_version == 1:
        args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
    elif args.header_version == 2:
        args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))

    if args.header_version > 1:

        # if filesize(args.dtb) == 0:
        #     raise ValueError("DTB image must not be empty.")

        args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
        args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
    pad_file(args.output, args.pagesize)
    return img_id


class ValidateStrLenAction(Action):
    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        if 'maxlen' not in kwargs:
            raise ValueError('maxlen must be set')
        self.maxlen = int(kwargs['maxlen'])
        del kwargs['maxlen']
        super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs)

    def __call__(self, parser, namespace, values, option_string=None):
        if len(values) > self.maxlen:
            raise ValueError(
                'String argument too long: max {0:d}, got {1:d}'.format(self.maxlen, len(values)))
        setattr(namespace, self.dest, values)


def write_padded_file(f_out, f_in, padding):
    if f_in is None:
        return
    f_out.write(f_in.read())
    pad_file(f_out, padding)


def parse_int(x):
    return int(x, 0)


def parse_os_version(x):
    match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
    if match:
        a = int(match.group(1))
        b = c = 0
        if match.lastindex >= 2:
            b = int(match.group(2))
        if match.lastindex == 3:
            c = int(match.group(3))
        # 7 bits allocated for each field
        assert a < 128
        assert b < 128
        assert c < 128
        return (a << 14) | (b << 7) | c
    return 0


def parse_os_patch_level(x):
    match = re.search(r'^(\d{4})-(\d{2})(?:-(\d{2}))?', x)
    if match:
        y = int(match.group(1)) - 2000
        m = int(match.group(2))
        # 7 bits allocated for the year, 4 bits for the month
        assert 0 <= y < 128
        assert 0 < m <= 12
        return (y << 4) | m
    return 0


def parse_cmdline():
    parser = ArgumentParser()
    parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'))
    parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
    parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
    parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
    recovery_dtbo_group = parser.add_mutually_exclusive_group()
    recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO',
                                     type=FileType('rb'))
    recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
                                     type=FileType('rb'), metavar='RECOVERY_ACPIO',
                                     dest='recovery_dtbo')
    parser.add_argument('--cmdline', help='extra arguments to be passed on the '
                        'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
    parser.add_argument('--vendor_cmdline',
                        help='kernel command line arguments contained in vendor boot',
                        default='', action=ValidateStrLenAction, maxlen=2048)
    parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
    parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
    parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int,
                        default=0x01000000)
    parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
                        default=0x00f00000)
    parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)

    parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
                        default=0)
    parser.add_argument('--os_patch_level', help='operating system patch level',
                        type=parse_os_patch_level, default=0)
    parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
    parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
                        maxlen=16)
    parser.add_argument('--pagesize', help='page size', type=parse_int,
                        choices=[2**i for i in range(11, 15)], default=2048)
    parser.add_argument('--id', help='print the image ID on standard output',
                        action='store_true')
    parser.add_argument('--header_version', help='boot image header version', type=parse_int,
                        default=0)
    parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'))
    parser.add_argument('--vendor_boot', help='vendor boot output file name', type=FileType('wb'))
    parser.add_argument('--vendor_ramdisk', help='path to the vendor ramdisk', type=FileType('rb'))

    return parser.parse_args()


def write_data(args, pagesize):
    write_padded_file(args.output, args.kernel, pagesize)
    write_padded_file(args.output, args.ramdisk, pagesize)
    write_padded_file(args.output, args.second, pagesize)

    if args.header_version > 0 and args.header_version < 3:
        write_padded_file(args.output, args.recovery_dtbo, pagesize)
    if args.header_version == 2:
        write_padded_file(args.output, args.dtb, pagesize)


def write_vendor_boot_data(args):
    write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
    write_padded_file(args.vendor_boot, args.dtb, args.pagesize)


def main():
    args = parse_cmdline()
    if args.vendor_boot is not None:
        if args.header_version < 3:
            raise ValueError('--vendor_boot not compatible with given header version')
        if args.vendor_ramdisk is None:
            raise ValueError('--vendor_ramdisk missing or invalid')
        write_vendor_boot_header(args)
        write_vendor_boot_data(args)
    if args.output is not None:
        if args.kernel is None:
            raise ValueError('kernel must be supplied when creating a boot image')
        if args.second is not None and args.header_version > 2:
            raise ValueError('--second not compatible with given header version')
        img_id = write_header(args)
        if args.header_version > 2:
            write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
        else:
            write_data(args, args.pagesize)
        if args.id and img_id is not None:
            # Python 2's struct.pack returns a string, but py3 returns bytes.
            if isinstance(img_id, str):
                img_id = [ord(x) for x in img_id]
            print('0x' + ''.join('{:02x}'.format(c) for c in img_id))


if __name__ == '__main__':
    main()

最后还有一个说明一下:

logo.bmp和logo_kernel.bmp 我也是拷贝了一份的。

相关推荐
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao3 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠4 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush44 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5204 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩4 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言