diff --git a/tools/rkcommon.c b/tools/rkcommon.c index 6595e02..1ea072b 100644 --- a/tools/rkcommon.c +++ b/tools/rkcommon.c @@ -41,25 +41,36 @@ struct header0_info { }; /** + * struct header1_info + */ +struct header1_info { + uint32_t magic; + uint32_t first_insn; +}; + +/** * struct spl_info - spl info for each chip * * @imagename: Image name(passed by "mkimage -n") * @spl_hdr: Boot ROM requires a 4-bytes spl header * @spl_size: Spl size(include extra 4-bytes spl header) * @spl_rc4: RC4 encode the SPL binary (same key as header) + * @spl_aarch64: Pad the header with an AArch64 'nop's to 8-bytes */ + struct spl_info { const char *imagename; const char *spl_hdr; const uint32_t spl_size; const bool spl_rc4; + const bool spl_aarch64; }; static struct spl_info spl_infos[] = { - { "rk3036", "RK30", 0x1000, false }, - { "rk3188", "RK31", 0x8000 - 0x800, true }, - { "rk3288", "RK32", 0x8000, false }, - { "rk3399", "RK33", 0x20000, false }, + { "rk3036", "RK30", 0x1000, false, false }, + { "rk3188", "RK31", 0x8000 - 0x800, true, false }, + { "rk3288", "RK32", 0x8000, false, false }, + { "rk3399", "RK33", 0x20000, false, true }, }; static unsigned char rc4_key[16] = { @@ -106,6 +117,16 @@ const char *rkcommon_get_spl_hdr(struct image_tool_params *params) return info->spl_hdr; } +const bool rkcommon_get_spl_hdr_padto8(struct image_tool_params *params) +{ + struct spl_info *info = rkcommon_get_spl_info(params->imagename); + + /* + * info would not be NULL, because of we checked params before. + */ + return info->spl_aarch64; +} + int rkcommon_get_spl_size(struct image_tool_params *params) { struct spl_info *info = rkcommon_get_spl_info(params->imagename); @@ -126,16 +147,12 @@ bool rkcommon_need_rc4_spl(struct image_tool_params *params) return info->spl_rc4; } -int rkcommon_set_header(void *buf, uint file_size, - struct image_tool_params *params) +static void rkcommon_set_header0(void *buf, uint file_size, + struct image_tool_params *params) { - struct header0_info *hdr; + struct header0_info *hdr = buf; - if (file_size > rkcommon_get_spl_size(params)) - return -ENOSPC; - - memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE); - hdr = (struct header0_info *)buf; + memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE); hdr->signature = RK_SIGNATURE; hdr->disable_rc4 = !rkcommon_need_rc4_spl(params); hdr->init_offset = RK_INIT_OFFSET; @@ -145,6 +162,31 @@ int rkcommon_set_header(void *buf, uint file_size, 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) +{ + 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); + + /* Set up the SPL name and add the AArch64 'nop' padding, if needed */ + memcpy(&hdr->magic, rkcommon_get_spl_hdr(params), RK_SPL_HDR_SIZE); + + /* + * Pad the 4-byte header to 8-bytes using an AArch64 'nop'. + * Note that AArch64 insns are always encoded as little-endian. + */ + if (rkcommon_get_spl_hdr_padto8(params)) + hdr->first_insn = cpu_to_le32(0xd503201f); + + if (rkcommon_need_rc4_spl(params)) + rkcommon_rc4_encode_spl(buf, RK_SPL_HDR_START, + params->file_size - RK_SPL_HDR_START); return 0; } @@ -161,3 +203,34 @@ void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size) remaining -= step; } } + +void rkcommon_vrec_header(struct image_tool_params *params, + struct image_type_params *tparams) +{ + /* + * The SPL image looks as follows: + * + * 0x0 header0 (see rkcommon.c) + * 0x800 spl_name ('RK30', ..., 'RK33') + * 0x804 first instruction to be executed + * (image start for AArch32, 'nop' for AArch64)) + * 0x808 second instruction to be executed + * (image start for AArch64) + * + * For AArch64 (ARMv8) payloads, we receive an input file that + * needs to start on an 8-byte boundary (natural alignment), so + * we need to put a NOP at 0x804. + * + * Depending on this, the header is either 0x804 or 0x808 bytes + * in length. + */ + if (rkcommon_get_spl_hdr_padto8(params)) + tparams->header_size = RK_SPL_HDR_START + 8; + else + tparams->header_size = RK_SPL_HDR_START + 4; + + /* Allocate, clear and install the header */ + tparams->hdr = malloc(tparams->header_size); + memset(tparams->hdr, 0, tparams->header_size); + tparams->header_size = tparams->header_size; +} diff --git a/tools/rkcommon.h b/tools/rkcommon.h index b4f6f32..3d64516 100644 --- a/tools/rkcommon.h +++ b/tools/rkcommon.h @@ -34,6 +34,19 @@ int rkcommon_check_params(struct image_tool_params *params); const char *rkcommon_get_spl_hdr(struct image_tool_params *params); /** + * rkcommon_get_spl_hdr_padto8() - check if we need to pad to 8 bytes + * + * Rockchip's bootrom starts execution right after the SPL header (i.e. + * at offset 4), but we can not reasonably align the test section of + * an AArch64 SPL at 4 bytes (as this would break natural alignment + * and any embedded constants might cause an alignment exception, which + * is illegal in privileged modes). + * + * Padding is (for now) assumed to occur with a single AArch64 'nop'. + */ +const bool rkcommon_get_spl_hdr_padto8(struct image_tool_params *params); + +/** * rkcommon_get_spl_size() - get spl size for a Rockchip boot image * * Different chip may have different sram size. And if we want to jump @@ -77,4 +90,14 @@ bool rkcommon_need_rc4_spl(struct image_tool_params *params); */ void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size); +/** + * rkcommon_vrec_header() - allocate memory for the header + * + * @params: Pointer to the tool params structure + * @tparams: Pointer tot the image type structure (for setting + * the header and header_size) + */ +void rkcommon_vrec_header(struct image_tool_params *params, + struct image_type_params *tparams); + #endif diff --git a/tools/rksd.c b/tools/rksd.c index e55c522..ac8a67d 100644 --- a/tools/rksd.c +++ b/tools/rksd.c @@ -13,8 +13,6 @@ #include "mkimage.h" #include "rkcommon.h" -static char dummy_hdr[RK_IMAGE_HEADER_LEN]; - static int rksd_verify_header(unsigned char *buf, int size, struct image_tool_params *params) { @@ -38,13 +36,6 @@ static void rksd_set_header(void *buf, struct stat *sbuf, int ifd, printf("Warning: SPL image is too large (size %#x) and will not boot\n", size); } - - memcpy(buf + RK_SPL_HDR_START, 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); } static int rksd_extract_subimage(void *buf, struct image_tool_params *params) @@ -66,10 +57,12 @@ static int rksd_vrec_header(struct image_tool_params *params, { int pad_size; + rkcommon_vrec_header(params, tparams); + pad_size = RK_SPL_HDR_START + rkcommon_get_spl_size(params); debug("pad_size %x\n", pad_size); - return pad_size - params->file_size; + return pad_size - params->file_size - tparams->header_size; } /* @@ -78,8 +71,8 @@ static int rksd_vrec_header(struct image_tool_params *params, U_BOOT_IMAGE_TYPE( rksd, "Rockchip SD Boot Image support", - RK_IMAGE_HEADER_LEN, - dummy_hdr, + 0, + NULL, rkcommon_check_params, rksd_verify_header, rksd_print_header, diff --git a/tools/rkspi.c b/tools/rkspi.c index 9fa43e8..d2d3fdd 100644 --- a/tools/rkspi.c +++ b/tools/rkspi.c @@ -17,8 +17,6 @@ enum { RKSPI_SECT_LEN = RK_BLK_SIZE * 4, }; -static char dummy_hdr[RK_IMAGE_HEADER_LEN]; - static int rkspi_verify_header(unsigned char *buf, int size, struct image_tool_params *params) { @@ -45,13 +43,6 @@ static void rkspi_set_header(void *buf, struct stat *sbuf, int ifd, size); } - memcpy(buf + RK_SPL_HDR_START, 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); - /* * 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 @@ -86,6 +77,8 @@ static int rkspi_vrec_header(struct image_tool_params *params, { int pad_size; + rkcommon_vrec_header(params, tparams); + pad_size = (rkcommon_get_spl_size(params) + 0x7ff) / 0x800 * 0x800; params->orig_file_size = pad_size; @@ -94,7 +87,7 @@ static int rkspi_vrec_header(struct image_tool_params *params, pad_size += RK_SPL_HDR_START; debug("pad_size %x\n", pad_size); - return pad_size - params->file_size; + return pad_size - params->file_size - tparams->header_size; } /* @@ -103,8 +96,8 @@ static int rkspi_vrec_header(struct image_tool_params *params, U_BOOT_IMAGE_TYPE( rkspi, "Rockchip SPI Boot Image support", - RK_IMAGE_HEADER_LEN, - dummy_hdr, + 0, + NULL, rkcommon_check_params, rkspi_verify_header, rkspi_print_header,