Home | History | Annotate | Download | only in tools
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2007-2011
      4  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
      5  * Tom Cubie <tangliang (at) allwinnertech.com>
      6  *
      7  * a simple tool to generate bootable image for sunxi platform.
      8  */
      9 #include <fcntl.h>
     10 #include <stdio.h>
     11 #include <unistd.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <errno.h>
     15 #include <sys/types.h>
     16 #include <sys/stat.h>
     17 #include "../arch/arm/include/asm/arch-sunxi/spl.h"
     18 
     19 #define STAMP_VALUE                     0x5F0A6C39
     20 
     21 /* check sum functon from sun4i boot code */
     22 int gen_check_sum(struct boot_file_head *head_p)
     23 {
     24 	uint32_t length;
     25 	uint32_t *buf;
     26 	uint32_t loop;
     27 	uint32_t i;
     28 	uint32_t sum;
     29 
     30 	length = le32_to_cpu(head_p->length);
     31 	if ((length & 0x3) != 0)	/* must 4-byte-aligned */
     32 		return -1;
     33 	buf = (uint32_t *)head_p;
     34 	head_p->check_sum = cpu_to_le32(STAMP_VALUE);	/* fill stamp */
     35 	loop = length >> 2;
     36 
     37 	/* calculate the sum */
     38 	for (i = 0, sum = 0; i < loop; i++)
     39 		sum += le32_to_cpu(buf[i]);
     40 
     41 	/* write back check sum */
     42 	head_p->check_sum = cpu_to_le32(sum);
     43 
     44 	return 0;
     45 }
     46 
     47 #define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1)
     48 #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
     49 
     50 #define SUNXI_SRAM_SIZE 0x8000	/* SoC with smaller size are limited before */
     51 #define SRAM_LOAD_MAX_SIZE (SUNXI_SRAM_SIZE - sizeof(struct boot_file_head))
     52 
     53 /*
     54  * BROM (at least on A10 and A20) requires NAND-images to be explicitly aligned
     55  * to a multiple of 8K, and rejects the image otherwise. MMC-images are fine
     56  * with 512B blocks. To cater for both, align to the largest of the two.
     57  */
     58 #define BLOCK_SIZE 0x2000
     59 
     60 struct boot_img {
     61 	struct boot_file_head header;
     62 	char code[SRAM_LOAD_MAX_SIZE];
     63 	char pad[BLOCK_SIZE];
     64 };
     65 
     66 int main(int argc, char *argv[])
     67 {
     68 	int fd_in, fd_out;
     69 	struct boot_img img;
     70 	unsigned file_size;
     71 	int count;
     72 	char *tool_name = argv[0];
     73 	char *default_dt = NULL;
     74 
     75 	/* a sanity check */
     76 	if ((sizeof(img.header) % 32) != 0) {
     77 		fprintf(stderr, "ERROR: the SPL header must be a multiple ");
     78 		fprintf(stderr, "of 32 bytes.\n");
     79 		return EXIT_FAILURE;
     80 	}
     81 
     82 	/* process optional command line switches */
     83 	while (argc >= 2 && argv[1][0] == '-') {
     84 		if (strcmp(argv[1], "--default-dt") == 0) {
     85 			if (argc >= 3) {
     86 				default_dt = argv[2];
     87 				argv += 2;
     88 				argc -= 2;
     89 				continue;
     90 			}
     91 			fprintf(stderr, "ERROR: no --default-dt arg\n");
     92 			return EXIT_FAILURE;
     93 		} else {
     94 			fprintf(stderr, "ERROR: bad option '%s'\n", argv[1]);
     95 			return EXIT_FAILURE;
     96 		}
     97 	}
     98 
     99 	if (argc < 3) {
    100 		printf("This program converts an input binary file to a sunxi bootable image.\n");
    101 		printf("\nUsage: %s [options] input_file output_file\n",
    102 		       tool_name);
    103 		printf("Where [options] may be:\n");
    104 		printf("  --default-dt arg         - 'arg' is the default device tree name\n");
    105 		printf("                             (CONFIG_DEFAULT_DEVICE_TREE).\n");
    106 		return EXIT_FAILURE;
    107 	}
    108 
    109 	fd_in = open(argv[1], O_RDONLY);
    110 	if (fd_in < 0) {
    111 		perror("Open input file");
    112 		return EXIT_FAILURE;
    113 	}
    114 
    115 	memset(&img, 0, sizeof(img));
    116 
    117 	/* get input file size */
    118 	file_size = lseek(fd_in, 0, SEEK_END);
    119 
    120 	if (file_size > SRAM_LOAD_MAX_SIZE) {
    121 		fprintf(stderr, "ERROR: File too large!\n");
    122 		return EXIT_FAILURE;
    123 	}
    124 
    125 	fd_out = open(argv[2], O_WRONLY | O_CREAT, 0666);
    126 	if (fd_out < 0) {
    127 		perror("Open output file");
    128 		return EXIT_FAILURE;
    129 	}
    130 
    131 	/* read file to buffer to calculate checksum */
    132 	lseek(fd_in, 0, SEEK_SET);
    133 	count = read(fd_in, img.code, file_size);
    134 	if (count != file_size) {
    135 		perror("Reading input image");
    136 		return EXIT_FAILURE;
    137 	}
    138 
    139 	/* fill the header */
    140 	img.header.b_instruction =	/* b instruction */
    141 		0xEA000000 |	/* jump to the first instr after the header */
    142 		((sizeof(struct boot_file_head) / sizeof(int) - 2)
    143 		 & 0x00FFFFFF);
    144 	memcpy(img.header.magic, BOOT0_MAGIC, 8);	/* no '0' termination */
    145 	img.header.length =
    146 		ALIGN(file_size + sizeof(struct boot_file_head), BLOCK_SIZE);
    147 	img.header.b_instruction = cpu_to_le32(img.header.b_instruction);
    148 	img.header.length = cpu_to_le32(img.header.length);
    149 
    150 	memcpy(img.header.spl_signature, SPL_SIGNATURE, 3); /* "sunxi" marker */
    151 	img.header.spl_signature[3] = SPL_HEADER_VERSION;
    152 
    153 	if (default_dt) {
    154 		if (strlen(default_dt) + 1 <= sizeof(img.header.string_pool)) {
    155 			strcpy((char *)img.header.string_pool, default_dt);
    156 			img.header.dt_name_offset =
    157 				cpu_to_le32(offsetof(struct boot_file_head,
    158 						     string_pool));
    159 		} else {
    160 			printf("WARNING: The SPL header is too small\n");
    161 			printf("         and has no space to store the dt name.\n");
    162 		}
    163 	}
    164 
    165 	gen_check_sum(&img.header);
    166 
    167 	count = write(fd_out, &img, le32_to_cpu(img.header.length));
    168 	if (count != le32_to_cpu(img.header.length)) {
    169 		perror("Writing output");
    170 		return EXIT_FAILURE;
    171 	}
    172 
    173 	close(fd_in);
    174 	close(fd_out);
    175 
    176 	return EXIT_SUCCESS;
    177 }
    178