uboot/tools/sunxi_egon.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2018 Arm Ltd.
   4 */
   5
   6#include "imagetool.h"
   7#include <image.h>
   8
   9#include <sunxi_image.h>
  10
  11/*
  12 * NAND requires 8K padding. SD/eMMC gets away with 512 bytes,
  13 * but let's use the larger padding to cover both.
  14 */
  15#define PAD_SIZE                        8192
  16
  17static int egon_check_params(struct image_tool_params *params)
  18{
  19        /* We just need a binary image file. */
  20        return !params->dflag;
  21}
  22
  23static int egon_verify_header(unsigned char *ptr, int image_size,
  24                              struct image_tool_params *params)
  25{
  26        const struct boot_file_head *header = (void *)ptr;
  27        uint32_t length;
  28
  29        /* First 4 bytes must be an ARM branch instruction. */
  30        if ((le32_to_cpu(header->b_instruction) & 0xff000000) != 0xea000000)
  31                return EXIT_FAILURE;
  32
  33        if (memcmp(header->magic, BOOT0_MAGIC, sizeof(header->magic)))
  34                return EXIT_FAILURE;
  35
  36        length = le32_to_cpu(header->length);
  37        /* Must be at least 512 byte aligned. */
  38        if (length & 511)
  39                return EXIT_FAILURE;
  40
  41        /*
  42         * Image could also contain U-Boot proper, so could be bigger.
  43         * But it must not be shorter.
  44         */
  45        if (image_size < length)
  46                return EXIT_FAILURE;
  47
  48        return EXIT_SUCCESS;
  49}
  50
  51static void egon_print_header(const void *buf)
  52{
  53        const struct boot_file_head *header = buf;
  54
  55        printf("Allwinner eGON image, size: %d bytes\n",
  56               le32_to_cpu(header->length));
  57
  58        if (memcmp(header->spl_signature, SPL_SIGNATURE, 3))
  59                return;
  60
  61        printf("\tSPL header version %d.%d\n",
  62               header->spl_signature[3] >> SPL_MINOR_BITS,
  63               header->spl_signature[3] & ((1U << SPL_MINOR_BITS) - 1));
  64        if (header->spl_signature[3] >= SPL_DT_HEADER_VERSION) {
  65                uint32_t dt_name_offs = le32_to_cpu(header->dt_name_offset);
  66
  67                if (dt_name_offs > 0)
  68                        printf("\tDT name: %s\n", (char *)buf + dt_name_offs);
  69        }
  70}
  71
  72static void egon_set_header(void *buf, struct stat *sbuf, int infd,
  73                            struct image_tool_params *params)
  74{
  75        struct boot_file_head *header = buf;
  76        uint32_t *buf32 = buf;
  77        uint32_t checksum = 0, value;
  78        int i;
  79
  80        /* Generate an ARM branch instruction to jump over the header. */
  81        value = 0xea000000 | (sizeof(struct boot_file_head) / 4 - 2);
  82        header->b_instruction = cpu_to_le32(value);
  83
  84        memcpy(header->magic, BOOT0_MAGIC, sizeof(header->magic));
  85        header->check_sum = cpu_to_le32(BROM_STAMP_VALUE);
  86        header->length = cpu_to_le32(params->file_size);
  87
  88        memcpy(header->spl_signature, SPL_SIGNATURE, 3);
  89        header->spl_signature[3] = SPL_ENV_HEADER_VERSION;
  90
  91        /* If an image name has been provided, use it as the DT name. */
  92        if (params->imagename && params->imagename[0]) {
  93                if (strlen(params->imagename) > sizeof(header->string_pool) - 1)
  94                        printf("WARNING: DT name too long for SPL header!\n");
  95                else {
  96                        strcpy((char *)header->string_pool, params->imagename);
  97                        value = offsetof(struct boot_file_head, string_pool);
  98                        header->dt_name_offset = cpu_to_le32(value);
  99                        header->spl_signature[3] = SPL_DT_HEADER_VERSION;
 100                }
 101        }
 102
 103        /* Calculate the checksum. Yes, it's that simple. */
 104        for (i = 0; i < sbuf->st_size / 4; i++)
 105                checksum += le32_to_cpu(buf32[i]);
 106        header->check_sum = cpu_to_le32(checksum);
 107}
 108
 109static int egon_check_image_type(uint8_t type)
 110{
 111        return type == IH_TYPE_SUNXI_EGON ? 0 : 1;
 112}
 113
 114static int egon_vrec_header(struct image_tool_params *params,
 115                            struct image_type_params *tparams)
 116{
 117        tparams->hdr = calloc(sizeof(struct boot_file_head), 1);
 118
 119        /* Return padding to 8K blocks. */
 120        return ALIGN(params->file_size, PAD_SIZE) - params->file_size;
 121}
 122
 123U_BOOT_IMAGE_TYPE(
 124        sunxi_egon,
 125        "Allwinner eGON Boot Image support",
 126        sizeof(struct boot_file_head),
 127        NULL,
 128        egon_check_params,
 129        egon_verify_header,
 130        egon_print_header,
 131        egon_set_header,
 132        NULL,
 133        egon_check_image_type,
 134        NULL,
 135        egon_vrec_header
 136);
 137