diff options
Diffstat (limited to 'tools/sfspl.c')
| -rw-r--r-- | tools/sfspl.c | 174 | 
1 files changed, 174 insertions, 0 deletions
| diff --git a/tools/sfspl.c b/tools/sfspl.c new file mode 100644 index 00000000000..ec18a0a77e7 --- /dev/null +++ b/tools/sfspl.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright Heinrich Schuchardt <heinrich.schuchardt@canonical.com> + * + * 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 <compiler.h> +#include <fcntl.h> +#include <u-boot/crc.h> +#include <unistd.h> +#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 */ +); | 
