1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright Heinrich Schuchardt <heinrich.schuchardt@canonical.com> 4 * 5 * The StarFive JH7110 requires to prepend a header to u-boot-spl.bin describing 6 * the payload length and CRC32. 7 * 8 * This module implements support in mkimage and dumpimage for this file format. 9 * 10 * StarFive's spl_tool available under GPL-2.0-and-later at 11 * https://github.com/starfive-tech/Tools implements writing the same file 12 * format and served as a reference. 13 */ 14 15#include <compiler.h> 16#include <fcntl.h> 17#include <u-boot/crc.h> 18#include <unistd.h> 19#include "imagetool.h" 20 21#define DEFAULT_VERSION 0x01010101 22#define DEFAULT_BACKUP 0x200000U 23#define DEFAULT_OFFSET 0x240 24 25/** 26 * struct spl_hdr - header for SPL on JH7110 27 * 28 * All fields are low-endian. 29 */ 30struct spl_hdr { 31 /** @offset: offset to SPL header (0x240) */ 32 unsigned int offset; 33 /** @bkp_offs: address of backup SPL, defaults to DEFAULT_BACKUP */ 34 unsigned int bkp_offs; 35 /** @zero1: set to zero */ 36 unsigned int zero1[159]; 37 /** @version: header version, defaults to DEFAULT_VERSION */ 38 unsigned int version; 39 /** @file_size: file size */ 40 unsigned int file_size; 41 /** @hdr_size: size of the file header (0x400) */ 42 unsigned int hdr_size; 43 /** @crc32: CRC32 */ 44 unsigned int crc32; 45 /** @zero2: set to zero */ 46 unsigned int zero2[91]; 47}; 48 49static int sfspl_check_params(struct image_tool_params *params) 50{ 51 /* Only the RISC-V architecture is supported */ 52 if (params->Aflag && params->arch != IH_ARCH_RISCV) 53 return EXIT_FAILURE; 54 55 return EXIT_SUCCESS; 56} 57 58static int sfspl_verify_header(unsigned char *buf, int size, 59 struct image_tool_params *params) 60{ 61 struct spl_hdr *hdr = (void *)buf; 62 unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); 63 unsigned int file_size = le32_to_cpu(hdr->file_size); 64 unsigned int crc = le32_to_cpu(hdr->crc32); 65 unsigned int crc_check; 66 67 if (size < 0 || 68 (size_t)size < sizeof(struct spl_hdr) || 69 (size_t)size < hdr_size + file_size) { 70 printf("Truncated file\n"); 71 return EXIT_FAILURE; 72 } 73 if (hdr->version != DEFAULT_VERSION) { 74 printf("Unknown file format version\n"); 75 return EXIT_FAILURE; 76 } 77 crc_check = crc32(0, &buf[hdr_size], size - hdr_size); 78 if (crc_check != crc) { 79 printf("Incorrect CRC32\n"); 80 return EXIT_FAILURE; 81 } 82 83 return EXIT_SUCCESS; 84} 85 86static void sfspl_print_header(const void *buf, 87 struct image_tool_params *params) 88{ 89 struct spl_hdr *hdr = (void *)buf; 90 unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); 91 unsigned int file_size = le32_to_cpu(hdr->file_size); 92 93 printf("Header size: %u\n", hdr_size); 94 printf("Payload size: %u\n", file_size); 95} 96 97static int sfspl_image_extract_subimage(void *ptr, 98 struct image_tool_params *params) 99{ 100 struct spl_hdr *hdr = (void *)ptr; 101 unsigned char *buf = ptr; 102 int fd, ret = EXIT_SUCCESS; 103 unsigned int hdr_size = le32_to_cpu(hdr->hdr_size); 104 unsigned int file_size = le32_to_cpu(hdr->file_size); 105 106 if (params->pflag) { 107 printf("Invalid image index %d\n", params->pflag); 108 return EXIT_FAILURE; 109 } 110 111 fd = open(params->outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); 112 if (fd == -1) { 113 perror("Cannot open file"); 114 return EXIT_FAILURE; 115 } 116 if (write(fd, &buf[hdr_size], file_size) != file_size) { 117 perror("Cannot write file"); 118 ret = EXIT_FAILURE; 119 } 120 close(fd); 121 122 return ret; 123} 124 125static int sfspl_check_image_type(uint8_t type) 126{ 127 if (type == IH_TYPE_STARFIVE_SPL) 128 return EXIT_SUCCESS; 129 130 return EXIT_FAILURE; 131} 132 133static void sfspl_set_header(void *buf, struct stat *sbuf, int infd, 134 struct image_tool_params *params) 135{ 136 struct spl_hdr *hdr = buf; 137 unsigned int file_size; 138 unsigned int crc; 139 140 file_size = params->file_size - sizeof(struct spl_hdr); 141 crc = crc32(0, &((unsigned char *)buf)[sizeof(struct spl_hdr)], 142 file_size); 143 144 hdr->offset = cpu_to_le32(DEFAULT_OFFSET); 145 hdr->bkp_offs = cpu_to_le32(DEFAULT_BACKUP); 146 hdr->version = cpu_to_le32(DEFAULT_VERSION); 147 hdr->file_size = cpu_to_le32(file_size); 148 hdr->hdr_size = cpu_to_le32(sizeof(struct spl_hdr)); 149 hdr->crc32 = cpu_to_le32(crc); 150} 151 152static int sfspl_vrec_header(struct image_tool_params *params, 153 struct image_type_params *tparams) 154{ 155 tparams->hdr = calloc(sizeof(struct spl_hdr), 1); 156 157 /* No padding */ 158 return 0; 159} 160 161U_BOOT_IMAGE_TYPE( 162 sfspl, /* id */ 163 "StarFive SPL Image", /* name */ 164 sizeof(struct spl_hdr), /* header_size */ 165 NULL, /* header */ 166 sfspl_check_params, /* check_params */ 167 sfspl_verify_header, /* verify header */ 168 sfspl_print_header, /* print header */ 169 sfspl_set_header, /* set header */ 170 sfspl_image_extract_subimage, /* extract_subimage */ 171 sfspl_check_image_type, /* check_image_type */ 172 NULL, /* fflag_handle */ 173 sfspl_vrec_header /* vrec_header */ 174); 175