uboot/tools/rkcommon.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2015 Google,  Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 *
   6 * (C) 2017 Theobroma Systems Design und Consulting GmbH
   7 *
   8 * Helper functions for Rockchip images
   9 */
  10
  11#include "imagetool.h"
  12#include <image.h>
  13#include <rc4.h>
  14#include "mkimage.h"
  15#include "rkcommon.h"
  16
  17#define DIV_ROUND_UP(n, d)      (((n) + (d) - 1) / (d))
  18
  19enum {
  20        RK_SIGNATURE            = 0x0ff0aa55,
  21};
  22
  23/**
  24 * struct header0_info - header block for boot ROM
  25 *
  26 * This is stored at SD card block 64 (where each block is 512 bytes, or at
  27 * the start of SPI flash. It is encoded with RC4.
  28 *
  29 * @signature:          Signature (must be RKSD_SIGNATURE)
  30 * @disable_rc4:        0 to use rc4 for boot image,  1 to use plain binary
  31 * @init_offset:        Offset in blocks of the SPL code from this header
  32 *                      block. E.g. 4 means 2KB after the start of this header.
  33 * Other fields are not used by U-Boot
  34 */
  35struct header0_info {
  36        uint32_t signature;
  37        uint8_t reserved[4];
  38        uint32_t disable_rc4;
  39        uint16_t init_offset;
  40        uint8_t reserved1[492];
  41        uint16_t init_size;
  42        uint16_t init_boot_size;
  43        uint8_t reserved2[2];
  44};
  45
  46/**
  47 * struct header1_info
  48 */
  49struct header1_info {
  50        uint32_t magic;
  51};
  52
  53/**
  54 * struct spl_info - spl info for each chip
  55 *
  56 * @imagename:          Image name(passed by "mkimage -n")
  57 * @spl_hdr:            Boot ROM requires a 4-bytes spl header
  58 * @spl_size:           Spl size(include extra 4-bytes spl header)
  59 * @spl_rc4:            RC4 encode the SPL binary (same key as header)
  60 */
  61
  62struct spl_info {
  63        const char *imagename;
  64        const char *spl_hdr;
  65        const uint32_t spl_size;
  66        const bool spl_rc4;
  67};
  68
  69static struct spl_info spl_infos[] = {
  70        { "rk3036", "RK30", 0x1000, false },
  71        { "rk3128", "RK31", 0x1800, false },
  72        { "rk3188", "RK31", 0x8000 - 0x800, true },
  73        { "rk322x", "RK32", 0x8000 - 0x1000, false },
  74        { "rk3288", "RK32", 0x8000, false },
  75        { "rk3328", "RK32", 0x8000 - 0x1000, false },
  76        { "rk3368", "RK33", 0x8000 - 0x1000, false },
  77        { "rk3399", "RK33", 0x30000 - 0x2000, false },
  78        { "rv1108", "RK11", 0x1800, false },
  79};
  80
  81static unsigned char rc4_key[16] = {
  82        124, 78, 3, 4, 85, 5, 9, 7,
  83        45, 44, 123, 56, 23, 13, 23, 17
  84};
  85
  86static struct spl_info *rkcommon_get_spl_info(char *imagename)
  87{
  88        int i;
  89
  90        if (!imagename)
  91                return NULL;
  92
  93        for (i = 0; i < ARRAY_SIZE(spl_infos); i++)
  94                if (!strncmp(imagename, spl_infos[i].imagename, 6))
  95                        return spl_infos + i;
  96
  97        return NULL;
  98}
  99
 100int rkcommon_check_params(struct image_tool_params *params)
 101{
 102        int i;
 103
 104        if (rkcommon_get_spl_info(params->imagename) != NULL)
 105                return EXIT_SUCCESS;
 106
 107        /*
 108         * If this is a operation (list or extract), the don't require
 109         * imagename to be set.
 110         */
 111        if (params->lflag || params->iflag)
 112                return EXIT_SUCCESS;
 113
 114        fprintf(stderr, "ERROR: imagename (%s) is not supported!\n",
 115                params->imagename ? params->imagename : "NULL");
 116
 117        fprintf(stderr, "Available imagename:");
 118        for (i = 0; i < ARRAY_SIZE(spl_infos); i++)
 119                fprintf(stderr, "\t%s", spl_infos[i].imagename);
 120        fprintf(stderr, "\n");
 121
 122        return EXIT_FAILURE;
 123}
 124
 125const char *rkcommon_get_spl_hdr(struct image_tool_params *params)
 126{
 127        struct spl_info *info = rkcommon_get_spl_info(params->imagename);
 128
 129        /*
 130         * info would not be NULL, because of we checked params before.
 131         */
 132        return info->spl_hdr;
 133}
 134
 135
 136int rkcommon_get_spl_size(struct image_tool_params *params)
 137{
 138        struct spl_info *info = rkcommon_get_spl_info(params->imagename);
 139
 140        /*
 141         * info would not be NULL, because of we checked params before.
 142         */
 143        return info->spl_size;
 144}
 145
 146bool rkcommon_need_rc4_spl(struct image_tool_params *params)
 147{
 148        struct spl_info *info = rkcommon_get_spl_info(params->imagename);
 149
 150        /*
 151         * info would not be NULL, because of we checked params before.
 152         */
 153        return info->spl_rc4;
 154}
 155
 156static void rkcommon_set_header0(void *buf, uint file_size,
 157                                 struct image_tool_params *params)
 158{
 159        struct header0_info *hdr = buf;
 160
 161        memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE);
 162        hdr->signature = RK_SIGNATURE;
 163        hdr->disable_rc4 = !rkcommon_need_rc4_spl(params);
 164        hdr->init_offset = RK_INIT_OFFSET;
 165
 166        hdr->init_size = DIV_ROUND_UP(file_size, RK_BLK_SIZE);
 167        /*
 168         * The init_size has to be a multiple of 4 blocks (i.e. of 2K)
 169         * or the BootROM will not boot the image.
 170         *
 171         * Note: To verify that this is not a legacy constraint, we
 172         *       rechecked this against the RK3399 BootROM.
 173         */
 174        hdr->init_size = ROUND(hdr->init_size, 4);
 175        /*
 176         * init_boot_size needs to be set, as it is read by the BootROM
 177         * to determine the size of the next-stage bootloader (e.g. U-Boot
 178         * proper), when used with the back-to-bootrom functionality.
 179         *
 180         * see https://lists.denx.de/pipermail/u-boot/2017-May/293267.html
 181         * for a more detailed explanation by Andy Yan
 182         */
 183        hdr->init_boot_size = hdr->init_size + RK_MAX_BOOT_SIZE / RK_BLK_SIZE;
 184
 185        rc4_encode(buf, RK_BLK_SIZE, rc4_key);
 186}
 187
 188int rkcommon_set_header(void *buf, uint file_size,
 189                        struct image_tool_params *params)
 190{
 191        struct header1_info *hdr = buf + RK_SPL_HDR_START;
 192
 193        if (file_size > rkcommon_get_spl_size(params))
 194                return -ENOSPC;
 195
 196        rkcommon_set_header0(buf, file_size, params);
 197
 198        /* Set up the SPL name (i.e. copy spl_hdr over) */
 199        memcpy(&hdr->magic, rkcommon_get_spl_hdr(params), RK_SPL_HDR_SIZE);
 200
 201        if (rkcommon_need_rc4_spl(params))
 202                rkcommon_rc4_encode_spl(buf, RK_SPL_HDR_START,
 203                                        params->file_size - RK_SPL_HDR_START);
 204
 205        return 0;
 206}
 207
 208static inline unsigned rkcommon_offset_to_spi(unsigned offset)
 209{
 210        /*
 211         * While SD/MMC images use a flat addressing, SPI images are padded
 212         * to use the first 2K of every 4K sector only.
 213         */
 214        return ((offset & ~0x7ff) << 1) + (offset & 0x7ff);
 215}
 216
 217static int rkcommon_parse_header(const void *buf, struct header0_info *header0,
 218                                 struct spl_info **spl_info)
 219{
 220        unsigned hdr1_offset;
 221        struct header1_info *hdr1_sdmmc, *hdr1_spi;
 222        int i;
 223
 224        if (spl_info)
 225                *spl_info = NULL;
 226
 227        /*
 228         * The first header (hdr0) is always RC4 encoded, so try to decrypt
 229         * with the well-known key.
 230         */
 231        memcpy((void *)header0, buf, sizeof(struct header0_info));
 232        rc4_encode((void *)header0, sizeof(struct header0_info), rc4_key);
 233
 234        if (header0->signature != RK_SIGNATURE)
 235                return -EPROTO;
 236
 237        /* We don't support RC4 encoded image payloads here, yet... */
 238        if (header0->disable_rc4 == 0)
 239                return -ENOSYS;
 240
 241        hdr1_offset = header0->init_offset * RK_BLK_SIZE;
 242        hdr1_sdmmc = (struct header1_info *)(buf + hdr1_offset);
 243        hdr1_spi = (struct header1_info *)(buf +
 244                                           rkcommon_offset_to_spi(hdr1_offset));
 245
 246        for (i = 0; i < ARRAY_SIZE(spl_infos); i++) {
 247                if (!memcmp(&hdr1_sdmmc->magic, spl_infos[i].spl_hdr, 4)) {
 248                        if (spl_info)
 249                                *spl_info = &spl_infos[i];
 250                        return IH_TYPE_RKSD;
 251                } else if (!memcmp(&hdr1_spi->magic, spl_infos[i].spl_hdr, 4)) {
 252                        if (spl_info)
 253                                *spl_info = &spl_infos[i];
 254                        return IH_TYPE_RKSPI;
 255                }
 256        }
 257
 258        return -1;
 259}
 260
 261int rkcommon_verify_header(unsigned char *buf, int size,
 262                           struct image_tool_params *params)
 263{
 264        struct header0_info header0;
 265        struct spl_info *img_spl_info, *spl_info;
 266        int ret;
 267
 268        ret = rkcommon_parse_header(buf, &header0, &img_spl_info);
 269
 270        /* If this is the (unimplemented) RC4 case, then rewrite the result */
 271        if (ret == -ENOSYS)
 272                return 0;
 273
 274        if (ret < 0)
 275                return ret;
 276
 277        /*
 278         * If no 'imagename' is specified via the commandline (e.g. if this is
 279         * 'dumpimage -l' w/o any further constraints), we accept any spl_info.
 280         */
 281        if (params->imagename == NULL)
 282                return 0;
 283
 284        /* Match the 'imagename' against the 'spl_hdr' found */
 285        spl_info = rkcommon_get_spl_info(params->imagename);
 286        if (spl_info && img_spl_info)
 287                return strcmp(spl_info->spl_hdr, img_spl_info->spl_hdr);
 288
 289        return -ENOENT;
 290}
 291
 292void rkcommon_print_header(const void *buf)
 293{
 294        struct header0_info header0;
 295        struct spl_info *spl_info;
 296        uint8_t image_type;
 297        int ret;
 298
 299        ret = rkcommon_parse_header(buf, &header0, &spl_info);
 300
 301        /* If this is the (unimplemented) RC4 case, then fail silently */
 302        if (ret == -ENOSYS)
 303                return;
 304
 305        if (ret < 0) {
 306                fprintf(stderr, "Error: image verification failed\n");
 307                return;
 308        }
 309
 310        image_type = ret;
 311
 312        printf("Image Type:   Rockchip %s (%s) boot image\n",
 313               spl_info->spl_hdr,
 314               (image_type == IH_TYPE_RKSD) ? "SD/MMC" : "SPI");
 315        printf("Data Size:    %d bytes\n", header0.init_size * RK_BLK_SIZE);
 316}
 317
 318void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size)
 319{
 320        unsigned int remaining = size;
 321
 322        while (remaining > 0) {
 323                int step = (remaining > RK_BLK_SIZE) ? RK_BLK_SIZE : remaining;
 324
 325                rc4_encode(buf + offset, step, rc4_key);
 326                offset += RK_BLK_SIZE;
 327                remaining -= step;
 328        }
 329}
 330
 331int rkcommon_vrec_header(struct image_tool_params *params,
 332                         struct image_type_params *tparams,
 333                         unsigned int alignment)
 334{
 335        unsigned int  unpadded_size;
 336        unsigned int  padded_size;
 337
 338        /*
 339         * The SPL image looks as follows:
 340         *
 341         * 0x0    header0 (see rkcommon.c)
 342         * 0x800  spl_name ('RK30', ..., 'RK33')
 343         *        (start of the payload for AArch64 payloads: we expect the
 344         *        first 4 bytes to be available for overwriting with our
 345         *        spl_name)
 346         * 0x804  first instruction to be executed
 347         *        (start of the image/payload for 32bit payloads)
 348         *
 349         * For AArch64 (ARMv8) payloads, natural alignment (8-bytes) is
 350         * required for its sections (so the image we receive needs to
 351         * have the first 4 bytes reserved for the spl_name).  Reserving
 352         * these 4 bytes is done using the BOOT0_HOOK infrastructure.
 353         *
 354         * The header is always at 0x800 (as we now use a payload
 355         * prepadded using the boot0 hook for all targets): the first
 356         * 4 bytes of these images can safely be overwritten using the
 357         * boot magic.
 358         */
 359        tparams->header_size = RK_SPL_HDR_START;
 360
 361        /* Allocate, clear and install the header */
 362        tparams->hdr = malloc(tparams->header_size);
 363        if (!tparams->hdr)
 364                return -ENOMEM;
 365        memset(tparams->hdr, 0, tparams->header_size);
 366
 367        /*
 368         * If someone passed in 0 for the alignment, we'd better handle
 369         * it correctly...
 370         */
 371        if (!alignment)
 372                alignment = 1;
 373
 374        unpadded_size = tparams->header_size + params->file_size;
 375        padded_size = ROUND(unpadded_size, alignment);
 376
 377        return padded_size - unpadded_size;
 378}
 379