[U-Boot] [PATCH v3 0/3] rockchip: mkimage: refactor rksd/rkspi padding calculation and add dumpimage support

We support booting both from SD/MMC images and SPI images on the RK3399-Q7 for different use-cases (e.g. external boot in development from the SD card, internal boot from MMC or SPI depending on whether the SPI flash is populated on any given configuration option).
In getting the SPI image support ready for production, we found a few areas that warranted improvements: - we had broken SPI bootstrap earlier in the changes introducting boot0-style images for the RK3399 (this needed fixing) - in fixing the broken SPI padding calculation, it became apparent that it's best to refactor and document things before we make the same mistake again in the future - with both SD/MMC and SPI images being used for various purposes by various people, the wrong image style was inadvertendly used in some tests... so we support for 'dumpimage' (i.e. verify_header and print_header) had to be added to quickly check the image type being handled
With v3, we pad the images to 2KB again, as this is required by the BootROM (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html).
Changes in v3: - (added patch) forces the alignment/padding to 2KB for SD images, as this would otherwise break the back-to-bootrom functionality - added in v3
Changes in v2: - (in rkcommon_verify_header): changed to use a standard error (i.e. from errno.h) to convey 'header0 signature does not match' [squash of: "rockchip: mkimage: don't mix standard errors and FDT"]
Philipp Tomsich (3): rockchip: mkimage: add support for verify_header/print_header rockchip: mkimage: force 2KB alignment for init_size rockchip: mkimage: set init_boot_size to avoid confusing the boot ROM
tools/rkcommon.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- tools/rkcommon.h | 20 +++++++++ tools/rksd.c | 35 ++++----------- tools/rkspi.c | 23 ++-------- 4 files changed, 158 insertions(+), 50 deletions(-)

The rockchip image generation was previously missing the ability to verify the generated header (and dump the image-type) without having to resort to hexdump or od. Experience in our testing has showed it to be very easy to get the rkspi and rksd images mixed up and the lab... so we add the necessary support to have dumpimage tell us what image type we're dealing with.
This change set adds the verify_header and print_header capability to the rksd/rkspi image drivers (through shared code in rkcommon).
As of now, we only support images fully that are not RC4-encoded for the SPL payload (i.e. header1 and payload). For RC4-encoded payloads, the outer header (header0) is checked, but no detection of whether this is a SD/MMC or SPI formatted payload takes place.
The output of dumpsys now prints the image type (spl_hdr), whether it is a SD/MMC or SPI image, and the (padded) size of the image: $ ./tools/dumpimage -l ./spl.img Image Type: Rockchip RK33 (SD/MMC) boot image ^^^^^^ SD/MMC vs. SPI indication ^^^^ spl_hdr indicated by the image Data Size: 79872 bytes
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v3: None Changes in v2: - (in rkcommon_verify_header): changed to use a standard error (i.e. from errno.h) to convey 'header0 signature does not match' [squash of: "rockchip: mkimage: don't mix standard errors and FDT"]
tools/rkcommon.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- tools/rkcommon.h | 19 +++++++++ tools/rksd.c | 29 +++----------- tools/rkspi.c | 21 ++-------- 4 files changed, 146 insertions(+), 42 deletions(-)
diff --git a/tools/rkcommon.c b/tools/rkcommon.c index f0bf0d4..f9d9421 100644 --- a/tools/rkcommon.c +++ b/tools/rkcommon.c @@ -2,6 +2,8 @@ * (C) Copyright 2015 Google, Inc * Written by Simon Glass sjg@chromium.org * + * (C) 2017 Theobroma Systems Design und Consulting GmbH + * * SPDX-License-Identifier: GPL-2.0+ * * Helper functions for Rockchip images @@ -201,7 +203,7 @@ int rkcommon_set_header(void *buf, uint file_size,
rkcommon_set_header0(buf, file_size, params);
- /* Set up the SPL name */ + /* 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)) @@ -211,6 +213,121 @@ int rkcommon_set_header(void *buf, uint file_size, return 0; }
+static inline unsigned rkcommon_offset_to_spi(unsigned offset) +{ + /* + * While SD/MMC images use a flat addressing, SPI images are padded + * to use the first 2K of every 4K sector only. + */ + return ((offset & ~0x7ff) << 1) + (offset & 0x7ff); +} + +static inline unsigned rkcommon_spi_to_offset(unsigned offset) +{ + return ((offset & ~0x7ff) >> 1) + (offset & 0x7ff); +} + +static int rkcommon_parse_header(const void *buf, struct header0_info *header0, + struct spl_info **spl_info) +{ + unsigned hdr1_offset; + struct header1_info *hdr1_sdmmc, *hdr1_spi; + int i; + + if (spl_info) + *spl_info = NULL; + + /* + * The first header (hdr0) is always RC4 encoded, so try to decrypt + * with the well-known key. + */ + memcpy((void *)header0, buf, sizeof(struct header0_info)); + rc4_encode((void *)header0, sizeof(struct header0_info), rc4_key); + + if (header0->signature != RK_SIGNATURE) + return -EPROTO; + + /* We don't support RC4 encoded image payloads here, yet... */ + if (header0->disable_rc4 == 0) + return -ENOSYS; + + hdr1_offset = header0->init_offset * RK_BLK_SIZE; + hdr1_sdmmc = (struct header1_info *)(buf + hdr1_offset); + hdr1_spi = (struct header1_info *)(buf + + rkcommon_offset_to_spi(hdr1_offset)); + + for (i = 0; i < ARRAY_SIZE(spl_infos); i++) { + if (!memcmp(&hdr1_sdmmc->magic, spl_infos[i].spl_hdr, 4)) { + if (spl_info) + *spl_info = &spl_infos[i]; + return IH_TYPE_RKSD; + } else if (!memcmp(&hdr1_spi->magic, spl_infos[i].spl_hdr, 4)) { + if (spl_info) + *spl_info = &spl_infos[i]; + return IH_TYPE_RKSPI; + } + } + + return -1; +} + +int rkcommon_verify_header(unsigned char *buf, int size, + struct image_tool_params *params) +{ + struct header0_info header0; + struct spl_info *img_spl_info, *spl_info; + int ret; + + ret = rkcommon_parse_header(buf, &header0, &img_spl_info); + + /* If this is the (unimplemented) RC4 case, then rewrite the result */ + if (ret == -ENOSYS) + return 0; + + if (ret < 0) + return ret; + + /* + * If no 'imagename' is specified via the commandline (e.g. if this is + * 'dumpimage -l' w/o any further constraints), we accept any spl_info. + */ + if (params->imagename == NULL) + return 0; + + /* Match the 'imagename' against the 'spl_hdr' found */ + spl_info = rkcommon_get_spl_info(params->imagename); + if (spl_info && img_spl_info) + return strcmp(spl_info->spl_hdr, img_spl_info->spl_hdr); + + return -ENOENT; +} + +void rkcommon_print_header(const void *buf) +{ + struct header0_info header0; + struct spl_info *spl_info; + uint8_t image_type; + int ret; + + ret = rkcommon_parse_header(buf, &header0, &spl_info); + + /* If this is the (unimplemented) RC4 case, then fail silently */ + if (ret == -ENOSYS) + return; + + if (ret < 0) { + fprintf(stderr, "Error: image verification failed\n"); + return; + } + + image_type = ret; + + 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); +} + void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size) { unsigned int remaining = size; diff --git a/tools/rkcommon.h b/tools/rkcommon.h index a21321f..75a4ed6 100644 --- a/tools/rkcommon.h +++ b/tools/rkcommon.h @@ -56,6 +56,25 @@ int rkcommon_set_header(void *buf, uint file_size, struct image_tool_params *params);
/** + * rkcommon_verify_header() - verify the header for a Rockchip boot image + * + * @buf: Pointer to the image file + * @file_size: Size of entire bootable image file (incl. all padding) + * @return 0 if OK + */ +int rkcommon_verify_header(unsigned char *buf, int size, + struct image_tool_params *params); + +/** + * rkcommon_print_header() - print the header for a Rockchip boot image + * + * This prints the header, spl_name and whether this is a SD/MMC or SPI image. + * + * @buf: Pointer to the image (can be a read-only file-mapping) + */ +void rkcommon_print_header(const void *buf); + +/** * rkcommon_need_rc4_spl() - check if rc4 encoded spl is required * * Some socs cannot disable the rc4-encryption of the spl binary. diff --git a/tools/rksd.c b/tools/rksd.c index 8627b6d..a880a26 100644 --- a/tools/rksd.c +++ b/tools/rksd.c @@ -13,29 +13,17 @@ #include "mkimage.h" #include "rkcommon.h"
-static int rksd_verify_header(unsigned char *buf, int size, - struct image_tool_params *params) -{ - return 0; -} - -static void rksd_print_header(const void *buf) -{ -} - static void rksd_set_header(void *buf, struct stat *sbuf, int ifd, - struct image_tool_params *params) + struct image_tool_params *params) { unsigned int size; int ret;
- printf("params->file_size %d\n", params->file_size); - printf("params->orig_file_size %d\n", params->orig_file_size); - /* * 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. + * '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); @@ -46,11 +34,6 @@ static void rksd_set_header(void *buf, struct stat *sbuf, int ifd, } }
-static int rksd_extract_subimage(void *buf, struct image_tool_params *params) -{ - return 0; -} - static int rksd_check_image_type(uint8_t type) { if (type == IH_TYPE_RKSD) @@ -78,10 +61,10 @@ U_BOOT_IMAGE_TYPE( 0, NULL, rkcommon_check_params, - rksd_verify_header, - rksd_print_header, + rkcommon_verify_header, + rkcommon_print_header, rksd_set_header, - rksd_extract_subimage, + NULL, rksd_check_image_type, NULL, rksd_vrec_header diff --git a/tools/rkspi.c b/tools/rkspi.c index 87bd1a9..f8a565d 100644 --- a/tools/rkspi.c +++ b/tools/rkspi.c @@ -17,16 +17,6 @@ enum { RKSPI_SECT_LEN = RK_BLK_SIZE * 4, };
-static int rkspi_verify_header(unsigned char *buf, int size, - struct image_tool_params *params) -{ - return 0; -} - -static void rkspi_print_header(const void *buf) -{ -} - static void rkspi_set_header(void *buf, struct stat *sbuf, int ifd, struct image_tool_params *params) { @@ -58,11 +48,6 @@ static void rkspi_set_header(void *buf, struct stat *sbuf, int ifd, } }
-static int rkspi_extract_subimage(void *buf, struct image_tool_params *params) -{ - return 0; -} - static int rkspi_check_image_type(uint8_t type) { if (type == IH_TYPE_RKSPI) @@ -112,10 +97,10 @@ U_BOOT_IMAGE_TYPE( 0, NULL, rkcommon_check_params, - rkspi_verify_header, - rkspi_print_header, + rkcommon_verify_header, + rkcommon_print_header, rkspi_set_header, - rkspi_extract_subimage, + NULL, rkspi_check_image_type, NULL, rkspi_vrec_header

The rockchip image generation was previously missing the ability to verify the generated header (and dump the image-type) without having to resort to hexdump or od. Experience in our testing has showed it to be very easy to get the rkspi and rksd images mixed up and the lab... so we add the necessary support to have dumpimage tell us what image type we're dealing with.
This change set adds the verify_header and print_header capability to the rksd/rkspi image drivers (through shared code in rkcommon).
As of now, we only support images fully that are not RC4-encoded for the SPL payload (i.e. header1 and payload). For RC4-encoded payloads, the outer header (header0) is checked, but no detection of whether this is a SD/MMC or SPI formatted payload takes place.
The output of dumpsys now prints the image type (spl_hdr), whether it is a SD/MMC or SPI image, and the (padded) size of the image: $ ./tools/dumpimage -l ./spl.img Image Type: Rockchip RK33 (SD/MMC) boot image ^^^^^^ SD/MMC vs. SPI indication ^^^^ spl_hdr indicated by the image Data Size: 79872 bytes
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com Acked-by: Simon Glass sjg@chromium.org
---
Changes in v3: None Changes in v2: - (in rkcommon_verify_header): changed to use a standard error (i.e. from errno.h) to convey 'header0 signature does not match' [squash of: "rockchip: mkimage: don't mix standard errors and FDT"]
tools/rkcommon.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- tools/rkcommon.h | 19 +++++++++ tools/rksd.c | 29 +++----------- tools/rkspi.c | 21 ++-------- 4 files changed, 146 insertions(+), 42 deletions(-)
Applied to u-boot-rockchip, thanks!

The Rockchip BootROM relies on init_size being aligned to 2KB (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html).
This pads the image to 2KB both for SD card images and SPI images and uses a common symbolic constant for the alignment.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: - (added patch) forces the alignment/padding to 2KB for SD images, as this would otherwise break the back-to-bootrom functionality
Changes in v2: None
tools/rkcommon.h | 1 + tools/rksd.c | 6 +++--- tools/rkspi.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/tools/rkcommon.h b/tools/rkcommon.h index 75a4ed6..8790f1c 100644 --- a/tools/rkcommon.h +++ b/tools/rkcommon.h @@ -10,6 +10,7 @@
enum { RK_BLK_SIZE = 512, + RK_INIT_SIZE_ALIGN = 2048, RK_INIT_OFFSET = 4, RK_MAX_BOOT_SIZE = 512 << 10, RK_SPL_HDR_START = RK_INIT_OFFSET * RK_BLK_SIZE, diff --git a/tools/rksd.c b/tools/rksd.c index a880a26..c56153d 100644 --- a/tools/rksd.c +++ b/tools/rksd.c @@ -46,10 +46,10 @@ static int rksd_vrec_header(struct image_tool_params *params, struct image_type_params *tparams) { /* - * Pad to the RK_BLK_SIZE (512 bytes) to be consistent with init_size - * being encoded in RK_BLK_SIZE units in header0 (see rkcommon.c). + * 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_BLK_SIZE); + return rkcommon_vrec_header(params, tparams, RK_INIT_SIZE_ALIGN); }
/* diff --git a/tools/rkspi.c b/tools/rkspi.c index f8a565d..4332ce1 100644 --- a/tools/rkspi.c +++ b/tools/rkspi.c @@ -63,7 +63,7 @@ static int rkspi_check_image_type(uint8_t type) static int rkspi_vrec_header(struct image_tool_params *params, struct image_type_params *tparams) { - int padding = rkcommon_vrec_header(params, tparams, 2048); + 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

On 30 May 2017 at 15:32, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
The Rockchip BootROM relies on init_size being aligned to 2KB (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html).
This pads the image to 2KB both for SD card images and SPI images and uses a common symbolic constant for the alignment.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- (added patch) forces the alignment/padding to 2KB for SD images, as this would otherwise break the back-to-bootrom functionality
Changes in v2: None
tools/rkcommon.h | 1 + tools/rksd.c | 6 +++--- tools/rkspi.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On 30 May 2017 at 15:32, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
The Rockchip BootROM relies on init_size being aligned to 2KB (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html).
This pads the image to 2KB both for SD card images and SPI images and uses a common symbolic constant for the alignment.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- (added patch) forces the alignment/padding to 2KB for SD images, as this would otherwise break the back-to-bootrom functionality
Changes in v2: None
tools/rkcommon.h | 1 + tools/rksd.c | 6 +++--- tools/rkspi.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot-rockchip, thanks!

This change restores the earlier setting of init_boot_size to include the maximum area covered by the the boot ROM of each chip for resolve issues with back-to-bootrom functionality reported by Kever and Heiko.
To ensure that we don't run into the same issue again in the future, I have updated the comments accordingly and added a reference to the mailing list archive (there's some very helpful info from Andy Yan that provides background on the BootROM requirements regarding these fields).
See https://lists.denx.de/pipermail/u-boot/2017-May/293267.html for some background (by Andy Yan) of how the BootROM processes this field.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
---
Changes in v3: - added in v3
Changes in v2: None
tools/rkcommon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/rkcommon.c b/tools/rkcommon.c index f9d9421..014cceb 100644 --- a/tools/rkcommon.c +++ b/tools/rkcommon.c @@ -184,11 +184,14 @@ static void rkcommon_set_header0(void *buf, uint file_size, */ hdr->init_size = ROUND(hdr->init_size, 4); /* - * The images we create do not contain the stage following the SPL as - * part of the SPL image, so the init_boot_size (which might have been - * read by Rockchip's miniloder) should be the same as the init_size. + * 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 + * proper), when used with the back-to-bootrom functionality. + * + * 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; + hdr->init_boot_size = hdr->init_size + RK_MAX_BOOT_SIZE / RK_BLK_SIZE;
rc4_encode(buf, RK_BLK_SIZE, rc4_key); }

On 30 May 2017 at 15:32, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This change restores the earlier setting of init_boot_size to include the maximum area covered by the the boot ROM of each chip for resolve issues with back-to-bootrom functionality reported by Kever and Heiko.
To ensure that we don't run into the same issue again in the future, I have updated the comments accordingly and added a reference to the mailing list archive (there's some very helpful info from Andy Yan that provides background on the BootROM requirements regarding these fields).
See https://lists.denx.de/pipermail/u-boot/2017-May/293267.html for some background (by Andy Yan) of how the BootROM processes this field.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- added in v3
Changes in v2: None
tools/rkcommon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On 30 May 2017 at 15:32, Philipp Tomsich philipp.tomsich@theobroma-systems.com wrote:
This change restores the earlier setting of init_boot_size to include the maximum area covered by the the boot ROM of each chip for resolve issues with back-to-bootrom functionality reported by Kever and Heiko.
To ensure that we don't run into the same issue again in the future, I have updated the comments accordingly and added a reference to the mailing list archive (there's some very helpful info from Andy Yan that provides background on the BootROM requirements regarding these fields).
See https://lists.denx.de/pipermail/u-boot/2017-May/293267.html for some background (by Andy Yan) of how the BootROM processes this field.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com
Changes in v3:
- added in v3
Changes in v2: None
tools/rkcommon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot-rockchip, thanks!

Hi Philipp:
2017-05-31 5:32 GMT+08:00 Philipp Tomsich < philipp.tomsich@theobroma-systems.com>:
We support booting both from SD/MMC images and SPI images on the RK3399-Q7 for different use-cases (e.g. external boot in development from the SD card, internal boot from MMC or SPI depending on whether the SPI flash is populated on any given configuration option).
In getting the SPI image support ready for production, we found a few areas that warranted improvements:
- we had broken SPI bootstrap earlier in the changes introducting boot0-style images for the RK3399 (this needed fixing)
- in fixing the broken SPI padding calculation, it became apparent that it's best to refactor and document things before we make the same mistake again in the future
- with both SD/MMC and SPI images being used for various purposes by various people, the wrong image style was inadvertendly used in some tests... so we support for 'dumpimage' (i.e. verify_header and print_header) had to be added to quickly check the image type being handled
With v3, we pad the images to 2KB again, as this is required by the BootROM (see https://lists.denx.de/pipermail/u-boot/2017-May/293268.html).
Changes in v3:
- (added patch) forces the alignment/padding to 2KB for SD images, as this would otherwise break the back-to-bootrom functionality
- added in v3
Changes in v2:
- (in rkcommon_verify_header): changed to use a standard error (i.e. from errno.h) to convey 'header0 signature does not match' [squash of: "rockchip: mkimage: don't mix standard errors and FDT"]
Philipp Tomsich (3): rockchip: mkimage: add support for verify_header/print_header rockchip: mkimage: force 2KB alignment for init_size rockchip: mkimage: set init_boot_size to avoid confusing the boot ROM
tools/rkcommon.c | 130 ++++++++++++++++++++++++++++++ ++++++++++++++++++++++--- tools/rkcommon.h | 20 +++++++++ tools/rksd.c | 35 ++++----------- tools/rkspi.c | 23 ++-------- 4 files changed, 158 insertions(+), 50 deletions(-)
-- 1.9.1
For patch (2)(3): Tested-by: Andy Yan andy.yan@rock-chips.com on
RV1108 evb board.
participants (4)
-
Andy Yan
-
Philipp Tomsich
-
Simon Glass
-
sjg@google.com