]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
rockchip: mkimage: pad the header to 8-bytes (using a 'nop') for RK3399
authorPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>
Wed, 15 Mar 2017 11:08:43 +0000 (12:08 +0100)
committerSimon Glass <sjg@chromium.org>
Wed, 5 Apr 2017 02:01:57 +0000 (20:01 -0600)
The RK3399 boot code (running as AArch64) poses a bit of a challenge
for SPL image generation:
 * The BootROM will start execution right after the 4-byte header (at
   the odd instruction word loaded into SRAM at 0xff8c2004, with the
   'RK33' boot magic residing at 0xff8c2000).
 * The default padding (during ELF generation) for AArch64 is 0x0,
   which is an illegal instruction and the .text section needs to be
   naturally aligned (someone might locate a 64bit constant relative
   to the section start and unaligned loads trigger a fault for all
   privileged modes of an ARMv8)... so we can't simply define the
   CONFIG_SPL_TEXT_BASE option to the odd address (0xff8c2004).
 * Finally, we don't want to change the values used for padding of
   the SPL .text section for all ARMv8 targets to the instruction
   word encoding 'nop', as this would affect all padding in this
   section and might hide errors that would otherwise quickly trigger
   an illegal insn exception.

To deal with this situation, we modify the rkimage generation to
 - understand the fact that the RK3399 needs to pad the header to an
   8 byte boundary using an AArch64 'nop'
 - the necessary logic to adjust the header_size (which controls the
   location where the payload is copied into the image) and to insert
   this padding (AArch64 insn words are always little-endian) into
   the image following the 4-byte header magic.

X-AffectedPlatforms: RK3399-Q7
Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Tested-by: Klaus Goger <klaus.goger@theobroma-systems.com>
tools/rkcommon.c
tools/rkcommon.h
tools/rksd.c
tools/rkspi.c

index 6595e02c1c5b87e9e4c6b659bcd8c90365e5193a..1ea072b8d4da500c791f1e53578510086254391d 100644 (file)
@@ -40,6 +40,14 @@ struct header0_info {
        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
  *
@@ -47,19 +55,22 @@ struct header0_info {
  * @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;
+}
index b4f6f327dc17f85be0933dc927336ca153b5de33..3d645168c2656ac39cbeb0580bdd479f5222f4f8 100644 (file)
@@ -33,6 +33,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
  *
@@ -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
index e55c52267fd8b189d139581d5003cf844c3d32bb..ac8a67d3bc80b1218f60400cb341b9e9ea315ef1 100644 (file)
@@ -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,
index 9fa43e8303468552153dd9b8234c838ac1a3d4c4..d2d3fdda424eadc545aac09253d65ae574268ec7 100644 (file)
@@ -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,