// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright Heinrich Schuchardt * * The StarFive JH7110 requires to prepend a header to u-boot-spl.bin describing * the payload length and CRC32. * * This module implements support in mkimage and dumpimage for this file format. * * StarFive's spl_tool available under GPL-2.0-and-later at * https://github.com/starfive-tech/Tools implements writing the same file * format and served as a reference. */ #include #include #include #include #include "imagetool.h" #define DEFAULT_VERSION 0x01010101 #define DEFAULT_BACKUP 0x200000U #define DEFAULT_OFFSET 0x240 /** * struct spl_hdr - header for SPL on JH7110 * * All fields are low-endian. */ struct spl_hdr { /** @offset: offset to SPL header (0x240) */ unsigned int offset; /** @bkp_offs: address of backup SPL, defaults to DEFAULT_BACKUP */ unsigned int bkp_offs; /** @zero1: set to zero */ unsigned int zero1[159]; /** @version: header version, defaults to DEFAULT_VERSION */ unsigned int version; /** @file_size: file size */ unsigned int file_size; /** @hdr_size: size of the file header (0x400) */ unsigned int hdr_size; /** @crc32: CRC32 */ unsigned int crc32; /** @zero2: set to zero */ unsigned int zero2[91]; }; static int sfspl_check_params(struct image_tool_params *params) { /* Only the RISC-V architecture is supported */ if (params->Aflag && params->arch != IH_ARCH_RISCV) return EXIT_FAILURE; return EXIT_SUCCESS; } static int sfspl_verify_header(unsigned char *buf, int size, struct image_tool_params *params) { struct spl_hdr *hdr = (void *)buf; unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); unsigned int file_size = le32_to_cpu(hdr->file_size); unsigned int crc = le32_to_cpu(hdr->crc32); unsigned int crc_check; if (size < 0 || (size_t)size < sizeof(struct spl_hdr) || (size_t)size < hdr_size + file_size) { printf("Truncated file\n"); return EXIT_FAILURE; } if (hdr->version != DEFAULT_VERSION) { printf("Unknown file format version\n"); return EXIT_FAILURE; } crc_check = crc32(0, &buf[hdr_size], size - hdr_size); if (crc_check != crc) { printf("Incorrect CRC32\n"); return EXIT_FAILURE; } return EXIT_SUCCESS; } static void sfspl_print_header(const void *buf, struct image_tool_params *params) { struct spl_hdr *hdr = (void *)buf; unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); unsigned int file_size = le32_to_cpu(hdr->file_size); printf("Header size: %u\n", hdr_size); printf("Payload size: %u\n", file_size); } static int sfspl_image_extract_subimage(void *ptr, struct image_tool_params *params) { struct spl_hdr *hdr = (void *)ptr; unsigned char *buf = ptr; int fd; unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); unsigned int file_size = le32_to_cpu(hdr->file_size); if (params->pflag) { printf("Invalid image index %d\n", params->pflag); return EXIT_FAILURE; } fd = open(params->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { perror("Can write file"); return EXIT_FAILURE; } if (write(fd, &buf[hdr_size], file_size) != file_size) { perror("Cannot write file"); return EXIT_FAILURE; } close(fd); return EXIT_SUCCESS; } static int sfspl_check_image_type(uint8_t type) { if (type == IH_TYPE_STARFIVE_SPL) return EXIT_SUCCESS; return EXIT_FAILURE; } static void sfspl_set_header(void *buf, struct stat *sbuf, int infd, struct image_tool_params *params) { struct spl_hdr *hdr = buf; unsigned int file_size; unsigned int crc; file_size = params->file_size - sizeof(struct spl_hdr); crc = crc32(0, &((unsigned char *)buf)[sizeof(struct spl_hdr)], file_size); hdr->offset = cpu_to_le32(DEFAULT_OFFSET); hdr->bkp_offs = cpu_to_le32(DEFAULT_BACKUP); hdr->version = cpu_to_le32(DEFAULT_VERSION); hdr->file_size = cpu_to_le32(file_size); hdr->hdr_size = cpu_to_le32(sizeof(struct spl_hdr)); hdr->crc32 = cpu_to_le32(crc); } static int sfspl_vrec_header(struct image_tool_params *params, struct image_type_params *tparams) { tparams->hdr = calloc(sizeof(struct spl_hdr), 1); /* No padding */ return 0; } U_BOOT_IMAGE_TYPE( sfspl, /* id */ "StarFive SPL Image", /* name */ sizeof(struct spl_hdr), /* header_size */ NULL, /* header */ sfspl_check_params, /* check_params */ sfspl_verify_header, /* verify header */ sfspl_print_header, /* print header */ sfspl_set_header, /* set header */ sfspl_image_extract_subimage, /* extract_subimage */ sfspl_check_image_type, /* check_image_type */ NULL, /* fflag_handle */ sfspl_vrec_header /* vrec_header */ );