uint8_t reserved2[2];
};
+/**
+ * struct header1_info
+ */
+struct header1_info {
+ uint32_t magic;
+ uint32_t first_insn;
+};
+
/**
* struct spl_info - spl info for each chip
*
* @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] = {
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);
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;
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;
}
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;
+}
*/
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
*
*/
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
#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)
{
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)
{
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;
}
/*
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,
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)
{
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
{
int pad_size;
+ rkcommon_vrec_header(params, tparams);
+
pad_size = (rkcommon_get_spl_size(params) + 0x7ff) / 0x800 * 0x800;
params->orig_file_size = pad_size;
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;
}
/*
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,