[PATCH v3 0/3] mkimage/rockchip: support packing optional second level boot-loader

When enabling back-to-bootrom, the bootrom would continue to load the second level boot-loader. And currently we are packing it by appending the generated image manually (with a predefined max size):
./firefly-rk3288/tools/mkimage -n rk3288 -T rksd -d \ firefly-rk3288/spl/u-boot-spl-dtb.bin out && \ cat firefly-rk3288/u-boot-dtb.bin >> out
This series add support of packing optional second level loader with mkimage tool: ./tools/mkimage -n rk3399 -T rksd -d \ rk3399_ddr_800MHz_v1.24.bin:rk3399_miniloader_v1.19.bin out
Changes in v3: Rule out hdr when checking spl size. (The bootrom would put hdr on stack.)
Changes in v2: Do rc4 encode for boot data when needed as well.
Jeffy Chen (3): rockchip: mkimage: support packing optional second level boot-loader doc: rockchip: document packing second level loader with mkimage rockchip: mkimage: fix wrong range of rc4 encoding for boot image
doc/README.rockchip | 11 +++ tools/imagetool.h | 1 + tools/mkimage.c | 8 ++ tools/rkcommon.c | 244 +++++++++++++++++++++++++++++++++++++++++++--------- tools/rkcommon.h | 18 ++-- tools/rkimage.c | 2 +- tools/rksd.c | 35 +------- tools/rkspi.c | 42 +++------ 8 files changed, 244 insertions(+), 117 deletions(-)

Support packing optional second level boot-loader:
$ ./tools/mkimage -n rk3399 -T rksd -d \ rk3399_ddr_800MHz_v1.24.bin:rk3399_miniloader_v1.19.bin out -v Adding Image rk3399_ddr_800MHz_v1.24.bin Size 116492(pad to 116736) Adding Image rk3399_miniloader_v1.19.bin Size 88060(pad to 88064) Image Type: Rockchip RK33 (SD/MMC) boot image Init Data Size: 116736 bytes Boot Data Size: 88064 bytes
Mainly parse init file and boot file from datafile option, copy them to the image with 2KB alignment.
Signed-off-by: Jeffy Chen jeffy.chen@rock-chips.com Reviewed-by: Kever Yang kever.yang@rock-chips.com ---
Changes in v3: Rule out hdr when checking spl size. (The bootrom would put hdr on stack.)
Changes in v2: Do rc4 encode for boot data when needed as well.
tools/imagetool.h | 1 + tools/mkimage.c | 8 ++ tools/rkcommon.c | 244 ++++++++++++++++++++++++++++++++++++++++++++---------- tools/rkcommon.h | 18 ++-- tools/rksd.c | 35 +------- tools/rkspi.c | 42 ++++------ 6 files changed, 232 insertions(+), 116 deletions(-)
diff --git a/tools/imagetool.h b/tools/imagetool.h index 2689a4004a..e1c778b0df 100644 --- a/tools/imagetool.h +++ b/tools/imagetool.h @@ -253,6 +253,7 @@ void pbl_load_uboot(int fd, struct image_tool_params *mparams); int zynqmpbif_copy_image(int fd, struct image_tool_params *mparams); int imx8image_copy_image(int fd, struct image_tool_params *mparams); int imx8mimage_copy_image(int fd, struct image_tool_params *mparams); +int rockchip_copy_image(int fd, struct image_tool_params *mparams);
#define ___cat(a, b) a ## b #define __cat(a, b) ___cat(a, b) diff --git a/tools/mkimage.c b/tools/mkimage.c index 4217188310..5f51d2cc89 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -544,6 +544,14 @@ int main(int argc, char **argv) ret = imx8mimage_copy_image(ifd, ¶ms); if (ret) return ret; + } else if ((params.type == IH_TYPE_RKSD) || + (params.type == IH_TYPE_RKSPI)) { + /* Rockchip has special Image format */ + int ret; + + ret = rockchip_copy_image(ifd, ¶ms); + if (ret) + return ret; } else { copy_file(ifd, params.datafile, pad_len); } diff --git a/tools/rkcommon.c b/tools/rkcommon.c index 0d908daee8..c6a48b0c1e 100644 --- a/tools/rkcommon.c +++ b/tools/rkcommon.c @@ -14,8 +14,6 @@ #include "mkimage.h" #include "rkcommon.h"
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - enum { RK_SIGNATURE = 0x0ff0aa55, }; @@ -80,6 +78,24 @@ static struct spl_info spl_infos[] = { { "rv1108", "RK11", 0x1800, false }, };
+/** + * struct spl_params - spl params parsed in check_params() + * + * @init_file: Init data file path + * @init_size: Aligned size of init data in bytes + * @boot_file: Boot data file path + * @boot_size: Aligned size of boot data in bytes + */ + +struct spl_params { + char *init_file; + uint32_t init_size; + char *boot_file; + uint32_t boot_size; +}; + +static struct spl_params spl_params = { 0 }; + static unsigned char rc4_key[16] = { 124, 78, 3, 4, 85, 5, 9, 7, 45, 44, 123, 56, 23, 13, 23, 17 @@ -99,12 +115,25 @@ static struct spl_info *rkcommon_get_spl_info(char *imagename) return NULL; }
-int rkcommon_check_params(struct image_tool_params *params) +static int rkcommon_get_aligned_size(struct image_tool_params *params, + const char *fname) { - int i; + int size;
- if (rkcommon_get_spl_info(params->imagename) != NULL) - return EXIT_SUCCESS; + size = imagetool_get_filesize(params, fname); + if (size < 0) + return -1; + + /* + * Pad to a 2KB alignment, as required for init/boot size by the ROM + * (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html) + */ + return ROUND(size, RK_SIZE_ALIGN); +} + +int rkcommon_check_params(struct image_tool_params *params) +{ + int i, spl_size;
/* * If this is a operation (list or extract), the don't require @@ -113,6 +142,40 @@ int rkcommon_check_params(struct image_tool_params *params) if (params->lflag || params->iflag) return EXIT_SUCCESS;
+ if (!rkcommon_get_spl_info(params->imagename)) + goto err_spl_info; + + spl_params.init_file = params->datafile; + + spl_params.boot_file = strchr(spl_params.init_file, ':'); + if (spl_params.boot_file) { + *spl_params.boot_file = '\0'; + spl_params.boot_file += 1; + } + + spl_params.init_size = + rkcommon_get_aligned_size(params, spl_params.init_file); + if (spl_params.init_size < 0) + return EXIT_FAILURE; + + /* Boot file is optional, and only for back-to-bootrom functionality. */ + if (spl_params.boot_file) { + spl_params.boot_size = + rkcommon_get_aligned_size(params, spl_params.boot_file); + if (spl_params.boot_size < 0) + return EXIT_FAILURE; + } + + if (spl_params.init_size > rkcommon_get_spl_size(params)) { + fprintf(stderr, + "Error: SPL image is too large (size %#x than %#x)\n", + spl_params.init_size, rkcommon_get_spl_size(params)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + +err_spl_info: fprintf(stderr, "ERROR: imagename (%s) is not supported!\n", params->imagename ? params->imagename : "NULL");
@@ -155,8 +218,7 @@ bool rkcommon_need_rc4_spl(struct image_tool_params *params) return info->spl_rc4; }
-static void rkcommon_set_header0(void *buf, uint file_size, - struct image_tool_params *params) +static void rkcommon_set_header0(void *buf, struct image_tool_params *params) { struct header0_info *hdr = buf;
@@ -164,16 +226,8 @@ static void rkcommon_set_header0(void *buf, uint file_size, hdr->signature = RK_SIGNATURE; hdr->disable_rc4 = !rkcommon_need_rc4_spl(params); hdr->init_offset = RK_INIT_OFFSET; + hdr->init_size = spl_params.init_size / RK_BLK_SIZE;
- hdr->init_size = DIV_ROUND_UP(file_size, RK_BLK_SIZE); - /* - * The init_size has to be a multiple of 4 blocks (i.e. of 2K) - * or the BootROM will not boot the image. - * - * Note: To verify that this is not a legacy constraint, we - * rechecked this against the RK3399 BootROM. - */ - hdr->init_size = ROUND(hdr->init_size, 4); /* * init_boot_size needs to be set, as it is read by the BootROM * to determine the size of the next-stage bootloader (e.g. U-Boot @@ -182,29 +236,36 @@ static void rkcommon_set_header0(void *buf, uint file_size, * see https://lists.denx.de/pipermail/u-boot/2017-May/293267.html * for a more detailed explanation by Andy Yan */ - hdr->init_boot_size = hdr->init_size + RK_MAX_BOOT_SIZE / RK_BLK_SIZE; + if (spl_params.boot_file) + hdr->init_boot_size = + hdr->init_size + spl_params.boot_size / RK_BLK_SIZE; + else + hdr->init_boot_size = + hdr->init_size + RK_MAX_BOOT_SIZE / RK_BLK_SIZE;
rc4_encode(buf, RK_BLK_SIZE, rc4_key); }
-int rkcommon_set_header(void *buf, uint file_size, - struct image_tool_params *params) +void rkcommon_set_header(void *buf, struct stat *sbuf, int ifd, + struct image_tool_params *params) { struct header1_info *hdr = buf + RK_SPL_HDR_START;
- if (file_size > rkcommon_get_spl_size(params)) - return -ENOSPC; - - rkcommon_set_header0(buf, file_size, params); + rkcommon_set_header0(buf, params);
/* Set up the SPL name (i.e. copy spl_hdr over) */ memcpy(&hdr->magic, rkcommon_get_spl_hdr(params), RK_SPL_HDR_SIZE);
if (rkcommon_need_rc4_spl(params)) rkcommon_rc4_encode_spl(buf, RK_SPL_HDR_START, - params->file_size - RK_SPL_HDR_START); + spl_params.init_size);
- return 0; + if (spl_params.boot_file) { + if (rkcommon_need_rc4_spl(params)) + rkcommon_rc4_encode_spl(buf + RK_SPL_HDR_START, + spl_params.init_size, + spl_params.boot_size); + } }
static inline unsigned rkcommon_offset_to_spi(unsigned offset) @@ -296,7 +357,7 @@ void rkcommon_print_header(const void *buf) struct header0_info header0; struct spl_info *spl_info; uint8_t image_type; - int ret; + int ret, boot_size;
ret = rkcommon_parse_header(buf, &header0, &spl_info);
@@ -314,7 +375,11 @@ void rkcommon_print_header(const void *buf) printf("Image Type: Rockchip %s (%s) boot image\n", spl_info->spl_hdr, (image_type == IH_TYPE_RKSD) ? "SD/MMC" : "SPI"); - printf("Data Size: %d bytes\n", header0.init_size * RK_BLK_SIZE); + printf("Init Data Size: %d bytes\n", header0.init_size * RK_BLK_SIZE); + + boot_size = (header0.init_boot_size - header0.init_size) * RK_BLK_SIZE; + if (boot_size != RK_MAX_BOOT_SIZE) + printf("Boot Data Size: %d bytes\n", boot_size); }
void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size) @@ -331,12 +396,8 @@ void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size) }
int rkcommon_vrec_header(struct image_tool_params *params, - struct image_type_params *tparams, - unsigned int alignment) + struct image_type_params *tparams) { - unsigned int unpadded_size; - unsigned int padded_size; - /* * The SPL image looks as follows: * @@ -362,19 +423,118 @@ int rkcommon_vrec_header(struct image_tool_params *params,
/* Allocate, clear and install the header */ tparams->hdr = malloc(tparams->header_size); - if (!tparams->hdr) - return -ENOMEM; + if (!tparams->hdr) { + fprintf(stderr, "%s: Can't alloc header: %s\n", + params->cmdname, strerror(errno)); + exit(EXIT_FAILURE); + } memset(tparams->hdr, 0, tparams->header_size);
/* - * If someone passed in 0 for the alignment, we'd better handle - * it correctly... + * We need to store the original file-size (i.e. before padding), as + * imagetool does not set this during its adjustment of file_size. */ - if (!alignment) - alignment = 1; + params->orig_file_size = tparams->header_size + + spl_params.init_size + spl_params.boot_size; + + params->file_size = ROUND(params->orig_file_size, RK_SIZE_ALIGN); + + /* Ignoring pad len, since we are using our own copy_image() */ + return 0; +} + +static int pad_file(struct image_tool_params *params, int ifd, int pad) +{ + uint8_t zeros[4096]; + + memset(zeros, 0, sizeof(zeros)); + + while (pad > 0) { + int todo = sizeof(zeros); + + if (todo > pad) + todo = pad; + if (write(ifd, (char *)&zeros, todo) != todo) { + fprintf(stderr, "%s: Write error on %s: %s\n", + params->cmdname, params->imagefile, + strerror(errno)); + return -1; + } + pad -= todo; + } + + return 0; +} + +static int copy_file(struct image_tool_params *params, int ifd, + const char *file, int padded_size) +{ + int dfd; + struct stat sbuf; + unsigned char *ptr; + int size; + + if (params->vflag) + fprintf(stderr, "Adding Image %s\n", file); + + dfd = open(file, O_RDONLY | O_BINARY); + if (dfd < 0) { + fprintf(stderr, "%s: Can't open %s: %s\n", + params->cmdname, file, strerror(errno)); + return -1; + }
- unpadded_size = tparams->header_size + params->file_size; - padded_size = ROUND(unpadded_size, alignment); + if (fstat(dfd, &sbuf) < 0) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + params->cmdname, file, strerror(errno)); + goto err_close; + } + + if (params->vflag) + fprintf(stderr, "Size %u(pad to %u)\n", + (int)sbuf.st_size, padded_size); + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr, "%s: Can't read %s: %s\n", + params->cmdname, file, strerror(errno)); + goto err_munmap; + } + + size = sbuf.st_size; + if (write(ifd, ptr, size) != size) { + fprintf(stderr, "%s: Write error on %s: %s\n", + params->cmdname, params->imagefile, strerror(errno)); + goto err_munmap; + } + + munmap((void *)ptr, sbuf.st_size); + close(dfd); + return pad_file(params, ifd, padded_size - size); + +err_munmap: + munmap((void *)ptr, sbuf.st_size); +err_close: + close(dfd); + return -1; +} + +int rockchip_copy_image(int ifd, struct image_tool_params *params) +{ + int ret; + + ret = copy_file(params, ifd, spl_params.init_file, + spl_params.init_size); + if (ret) + return ret; + + if (spl_params.boot_file) { + ret = copy_file(params, ifd, spl_params.boot_file, + spl_params.boot_size); + if (ret) + return ret; + }
- return padded_size - unpadded_size; + return pad_file(params, ifd, + params->file_size - params->orig_file_size); } diff --git a/tools/rkcommon.h b/tools/rkcommon.h index 47f47a52aa..93518824a5 100644 --- a/tools/rkcommon.h +++ b/tools/rkcommon.h @@ -9,13 +9,11 @@
enum { RK_BLK_SIZE = 512, - RK_INIT_SIZE_ALIGN = 2048, + RK_SIZE_ALIGN = 2048, RK_INIT_OFFSET = 4, RK_MAX_BOOT_SIZE = 512 << 10, RK_SPL_HDR_START = RK_INIT_OFFSET * RK_BLK_SIZE, RK_SPL_HDR_SIZE = 4, - RK_SPL_START = RK_SPL_HDR_START + RK_SPL_HDR_SIZE, - RK_IMAGE_HEADER_LEN = RK_SPL_START, };
/** @@ -49,11 +47,9 @@ int rkcommon_get_spl_size(struct image_tool_params *params); * This sets up a 2KB header which can be interpreted by the Rockchip boot ROM. * * @buf: Pointer to header place (must be at least 2KB in size) - * @file_size: Size of the file we want the boot ROM to load, in bytes - * @return 0 if OK, -ENOSPC if too large */ -int rkcommon_set_header(void *buf, uint file_size, - struct image_tool_params *params); +void rkcommon_set_header(void *buf, struct stat *sbuf, int ifd, + struct image_tool_params *params);
/** * rkcommon_verify_header() - verify the header for a Rockchip boot image @@ -102,14 +98,10 @@ void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size); * @params: Pointer to the tool params structure * @tparams: Pointer tot the image type structure (for setting * the header and header_size) - * @alignment: Alignment (a power of two) that the image should be - * padded to (e.g. 512 if we want to align with SD/MMC - * blocksizes or 2048 for the SPI format) * - * @return bytes of padding required/added (does not include the header_size) + * @return 0 (always) */ int rkcommon_vrec_header(struct image_tool_params *params, - struct image_type_params *tparams, - unsigned int alignment); + struct image_type_params *tparams);
#endif diff --git a/tools/rksd.c b/tools/rksd.c index 24411d863a..7d46a1b07b 100644 --- a/tools/rksd.c +++ b/tools/rksd.c @@ -12,27 +12,6 @@ #include "mkimage.h" #include "rkcommon.h"
-static void rksd_set_header(void *buf, struct stat *sbuf, int ifd, - struct image_tool_params *params) -{ - unsigned int size; - int ret; - - /* - * We need to calculate this using 'RK_SPL_HDR_START' and not using - * 'tparams->header_size', as the additional byte inserted when - * 'is_boot0' is true counts towards the payload (and not towards the - * header). - */ - size = params->file_size - RK_SPL_HDR_START; - ret = rkcommon_set_header(buf, size, params); - if (ret) { - /* TODO(sjg@chromium.org): This method should return an error */ - printf("Warning: SPL image is too large (size %#x) and will " - "not boot\n", size); - } -} - static int rksd_check_image_type(uint8_t type) { if (type == IH_TYPE_RKSD) @@ -41,16 +20,6 @@ static int rksd_check_image_type(uint8_t type) return EXIT_FAILURE; }
-static int rksd_vrec_header(struct image_tool_params *params, - struct image_type_params *tparams) -{ - /* - * Pad to a 2KB alignment, as required for init_size by the ROM - * (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html) - */ - return rkcommon_vrec_header(params, tparams, RK_INIT_SIZE_ALIGN); -} - /* * rk_sd parameters */ @@ -62,9 +31,9 @@ U_BOOT_IMAGE_TYPE( rkcommon_check_params, rkcommon_verify_header, rkcommon_print_header, - rksd_set_header, + rkcommon_set_header, NULL, rksd_check_image_type, NULL, - rksd_vrec_header + rkcommon_vrec_header ); diff --git a/tools/rkspi.c b/tools/rkspi.c index faa18fcd18..f2530f7bde 100644 --- a/tools/rkspi.c +++ b/tools/rkspi.c @@ -21,22 +21,20 @@ static void rkspi_set_header(void *buf, struct stat *sbuf, int ifd, { int sector; unsigned int size; - int ret;
size = params->orig_file_size; - ret = rkcommon_set_header(buf, size, params); - debug("size %x\n", size); - if (ret) { - /* TODO(sjg@chromium.org): This method should return an error */ - printf("Warning: SPL image is too large (size %#x) and will " - "not boot\n", size); - } + + rkcommon_set_header(buf, sbuf, ifd, params);
/* * Spread the image out so we only use the first 2KB of each 4KB * region. This is a feature of the SPI format required by the Rockchip * boot ROM. Its rationale is unknown. */ + if (params->vflag) + fprintf(stderr, "Spreading spi image from %u to %u\n", + size, params->file_size); + for (sector = size / RKSPI_SECT_LEN - 1; sector >= 0; sector--) { debug("sector %u\n", sector); memmove(buf + sector * RKSPI_SECT_LEN * 2, @@ -56,35 +54,23 @@ static int rkspi_check_image_type(uint8_t type) }
/* - * The SPI payload needs to be padded out to make space for odd half-sector - * layout used in flash (i.e. only the first 2K of each 4K sector is used). + * The SPI payload needs to make space for odd half-sector layout used in flash + * (i.e. only the first 2K of each 4K sector is used). */ static int rkspi_vrec_header(struct image_tool_params *params, struct image_type_params *tparams) { - int padding = rkcommon_vrec_header(params, tparams, RK_INIT_SIZE_ALIGN); - /* - * The file size has not been adjusted at this point (our caller will - * eventually add the header/padding to the file_size), so we need to - * add up the header_size, file_size and padding ourselves. - */ - int padded_size = tparams->header_size + params->file_size + padding; - - /* - * We need to store the original file-size (i.e. before padding), as - * imagetool does not set this during its adjustment of file_size. - */ - params->orig_file_size = padded_size; + rkcommon_vrec_header(params, tparams);
/* * Converting to the SPI format (i.e. splitting each 4K page into two * 2K subpages and then padding these 2K pages up to take a complete - * 4K sector again) will will double the image size. - * - * Thus we return the padded_size as an additional padding requirement - * (be sure to add this to the padding returned from the common code). + * 4K sector again) which will double the image size. */ - return padded_size + padding; + params->file_size = ROUND(params->file_size, RKSPI_SECT_LEN) << 1; + + /* Ignoring pad len, since we are using our own copy_image() */ + return 0; }
/*

Add documentation about packing optional second level boot-loader with mkimage tool.
Signed-off-by: Jeffy Chen jeffy.chen@rock-chips.com Reviewed-by: Kever Yang kever.yang@rock-chips.com ---
Changes in v3: None Changes in v2: None
doc/README.rockchip | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/doc/README.rockchip b/doc/README.rockchip index dae4ebc8e4..e54b7b8df5 100644 --- a/doc/README.rockchip +++ b/doc/README.rockchip @@ -340,6 +340,12 @@ You can create the image via the following operations: cat firefly-rk3288/u-boot-dtb.bin >> out && \ sudo dd if=out of=/dev/sdc seek=64
+Or: + ./firefly-rk3288/tools/mkimage -n rk3288 -T rksd -d \ + firefly-rk3288/spl/u-boot-spl-dtb.bin:firefly-rk3288/u-boot-dtb.bin \ + out && \ + sudo dd if=out of=/dev/sdc seek=64 + If you have an HDMI cable attached you should see a video console.
For evb_rk3036 board: @@ -347,6 +353,11 @@ For evb_rk3036 board: cat evb-rk3036/u-boot-dtb.bin >> out && \ sudo dd if=out of=/dev/sdc seek=64
+Or: + ./evb-rk3036/tools/mkimage -n rk3036 -T rksd -d \ + evb-rk3036/spl/u-boot-spl.bin:evb-rk3036/u-boot-dtb.bin out && \ + sudo dd if=out of=/dev/sdc seek=64 + Note: rk3036 SDMMC and debug uart use the same iomux, so if you boot from SD, the debug uart must be disabled

The rc4 encoding should cover spl header as well, and the file_size contains spl header too.
Signed-off-by: Jeffy Chen jeffy.chen@rock-chips.com Reviewed-by: Kever Yang kever.yang@rock-chips.com ---
Changes in v3: None Changes in v2: None
tools/rkimage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/rkimage.c b/tools/rkimage.c index ae50de55c9..1c5540b1c3 100644 --- a/tools/rkimage.c +++ b/tools/rkimage.c @@ -18,7 +18,7 @@ static void rkimage_set_header(void *buf, struct stat *sbuf, int ifd, memcpy(buf, rkcommon_get_spl_hdr(params), RK_SPL_HDR_SIZE);
if (rkcommon_need_rc4_spl(params)) - rkcommon_rc4_encode_spl(buf, 4, params->file_size); + rkcommon_rc4_encode_spl(buf, 0, params->file_size); }
static int rkimage_check_image_type(uint8_t type)
participants (1)
-
Jeffy Chen