Blame view

tools/mksunxiboot.c 4.66 KB
50827a599   Ian Campbell   sunxi: non-FEL SP...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * (C) Copyright 2007-2011
   * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
   * Tom Cubie <tangliang@allwinnertech.com>
   *
   * a simple tool to generate bootable image for sunxi platform.
   *
   * SPDX-License-Identifier:	GPL-2.0+
   */
  #include <fcntl.h>
  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <string.h>
  #include <errno.h>
  #include <sys/types.h>
  #include <sys/stat.h>
fed329aeb   Stefan Brüns   tools: add mksunx...
18
  #include "../arch/arm/include/asm/arch-sunxi/spl.h"
50827a599   Ian Campbell   sunxi: non-FEL SP...
19

50827a599   Ian Campbell   sunxi: non-FEL SP...
20
21
22
23
24
25
26
27
28
29
  #define STAMP_VALUE                     0x5F0A6C39
  
  /* check sum functon from sun4i boot code */
  int gen_check_sum(struct boot_file_head *head_p)
  {
  	uint32_t length;
  	uint32_t *buf;
  	uint32_t loop;
  	uint32_t i;
  	uint32_t sum;
c924e2a80   Siarhei Siamashka   tools: mksunxiboo...
30
  	length = le32_to_cpu(head_p->length);
50827a599   Ian Campbell   sunxi: non-FEL SP...
31
32
33
  	if ((length & 0x3) != 0)	/* must 4-byte-aligned */
  		return -1;
  	buf = (uint32_t *)head_p;
c924e2a80   Siarhei Siamashka   tools: mksunxiboo...
34
  	head_p->check_sum = cpu_to_le32(STAMP_VALUE);	/* fill stamp */
50827a599   Ian Campbell   sunxi: non-FEL SP...
35
36
37
38
  	loop = length >> 2;
  
  	/* calculate the sum */
  	for (i = 0, sum = 0; i < loop; i++)
c924e2a80   Siarhei Siamashka   tools: mksunxiboo...
39
  		sum += le32_to_cpu(buf[i]);
50827a599   Ian Campbell   sunxi: non-FEL SP...
40
41
  
  	/* write back check sum */
c924e2a80   Siarhei Siamashka   tools: mksunxiboo...
42
  	head_p->check_sum = cpu_to_le32(sum);
50827a599   Ian Campbell   sunxi: non-FEL SP...
43
44
45
46
47
48
  
  	return 0;
  }
  
  #define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1)
  #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
45e2d0676   Andre Przywara   tools: mksunxiboo...
49
50
  #define SUNXI_SRAM_SIZE 0x8000	/* SoC with smaller size are limited before */
  #define SRAM_LOAD_MAX_SIZE (SUNXI_SRAM_SIZE - sizeof(struct boot_file_head))
1f6f61fe4   Daniel Kochmański   sunxi/nand: chang...
51
52
53
54
55
56
57
  
  /*
   * BROM (at least on A10 and A20) requires NAND-images to be explicitly aligned
   * to a multiple of 8K, and rejects the image otherwise. MMC-images are fine
   * with 512B blocks. To cater for both, align to the largest of the two.
   */
  #define BLOCK_SIZE 0x2000
50827a599   Ian Campbell   sunxi: non-FEL SP...
58
59
60
61
62
63
64
65
66
67
68
  
  struct boot_img {
  	struct boot_file_head header;
  	char code[SRAM_LOAD_MAX_SIZE];
  	char pad[BLOCK_SIZE];
  };
  
  int main(int argc, char *argv[])
  {
  	int fd_in, fd_out;
  	struct boot_img img;
4ba73a5ac   Hans de Goede   sunxi: mksunxiboo...
69
  	unsigned file_size;
50827a599   Ian Campbell   sunxi: non-FEL SP...
70
  	int count;
7f0ef5a94   Siarhei Siamashka   sunxi: Store the ...
71
72
  	char *tool_name = argv[0];
  	char *default_dt = NULL;
50827a599   Ian Campbell   sunxi: non-FEL SP...
73

7f0ef5a94   Siarhei Siamashka   sunxi: Store the ...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  	/* a sanity check */
  	if ((sizeof(img.header) % 32) != 0) {
  		fprintf(stderr, "ERROR: the SPL header must be a multiple ");
  		fprintf(stderr, "of 32 bytes.
  ");
  		return EXIT_FAILURE;
  	}
  
  	/* process optional command line switches */
  	while (argc >= 2 && argv[1][0] == '-') {
  		if (strcmp(argv[1], "--default-dt") == 0) {
  			if (argc >= 3) {
  				default_dt = argv[2];
  				argv += 2;
  				argc -= 2;
  				continue;
  			}
  			fprintf(stderr, "ERROR: no --default-dt arg
  ");
  			return EXIT_FAILURE;
  		} else {
  			fprintf(stderr, "ERROR: bad option '%s'
  ", argv[1]);
  			return EXIT_FAILURE;
  		}
  	}
  
  	if (argc < 3) {
  		printf("This program converts an input binary file to a sunxi bootable image.
  ");
  		printf("
  Usage: %s [options] input_file output_file
  ",
  		       tool_name);
  		printf("Where [options] may be:
  ");
  		printf("  --default-dt arg         - 'arg' is the default device tree name
  ");
  		printf("                             (CONFIG_DEFAULT_DEVICE_TREE).
  ");
50827a599   Ian Campbell   sunxi: non-FEL SP...
114
115
116
117
118
119
120
121
  		return EXIT_FAILURE;
  	}
  
  	fd_in = open(argv[1], O_RDONLY);
  	if (fd_in < 0) {
  		perror("Open input file");
  		return EXIT_FAILURE;
  	}
bfb05d018   Siarhei Siamashka   sunxi: Ensure tha...
122
  	memset(&img, 0, sizeof(img));
50827a599   Ian Campbell   sunxi: non-FEL SP...
123
124
125
126
127
128
129
130
  
  	/* get input file size */
  	file_size = lseek(fd_in, 0, SEEK_END);
  
  	if (file_size > SRAM_LOAD_MAX_SIZE) {
  		fprintf(stderr, "ERROR: File too large!
  ");
  		return EXIT_FAILURE;
50827a599   Ian Campbell   sunxi: non-FEL SP...
131
132
133
134
135
136
137
138
139
140
  	}
  
  	fd_out = open(argv[2], O_WRONLY | O_CREAT, 0666);
  	if (fd_out < 0) {
  		perror("Open output file");
  		return EXIT_FAILURE;
  	}
  
  	/* read file to buffer to calculate checksum */
  	lseek(fd_in, 0, SEEK_SET);
4ba73a5ac   Hans de Goede   sunxi: mksunxiboo...
141
142
  	count = read(fd_in, img.code, file_size);
  	if (count != file_size) {
50827a599   Ian Campbell   sunxi: non-FEL SP...
143
144
145
146
147
148
149
150
151
152
153
  		perror("Reading input image");
  		return EXIT_FAILURE;
  	}
  
  	/* fill the header */
  	img.header.b_instruction =	/* b instruction */
  		0xEA000000 |	/* jump to the first instr after the header */
  		((sizeof(struct boot_file_head) / sizeof(int) - 2)
  		 & 0x00FFFFFF);
  	memcpy(img.header.magic, BOOT0_MAGIC, 8);	/* no '0' termination */
  	img.header.length =
4ba73a5ac   Hans de Goede   sunxi: mksunxiboo...
154
  		ALIGN(file_size + sizeof(struct boot_file_head), BLOCK_SIZE);
c924e2a80   Siarhei Siamashka   tools: mksunxiboo...
155
156
  	img.header.b_instruction = cpu_to_le32(img.header.b_instruction);
  	img.header.length = cpu_to_le32(img.header.length);
a18843817   Bernhard Nortmann   sunxi: (mksunxibo...
157
158
159
  
  	memcpy(img.header.spl_signature, SPL_SIGNATURE, 3); /* "sunxi" marker */
  	img.header.spl_signature[3] = SPL_HEADER_VERSION;
7f0ef5a94   Siarhei Siamashka   sunxi: Store the ...
160
161
162
163
164
165
166
167
168
169
170
171
172
  	if (default_dt) {
  		if (strlen(default_dt) + 1 <= sizeof(img.header.string_pool)) {
  			strcpy((char *)img.header.string_pool, default_dt);
  			img.header.dt_name_offset =
  				cpu_to_le32(offsetof(struct boot_file_head,
  						     string_pool));
  		} else {
  			printf("WARNING: The SPL header is too small
  ");
  			printf("         and has no space to store the dt name.
  ");
  		}
  	}
50827a599   Ian Campbell   sunxi: non-FEL SP...
173
  	gen_check_sum(&img.header);
c924e2a80   Siarhei Siamashka   tools: mksunxiboo...
174
175
  	count = write(fd_out, &img, le32_to_cpu(img.header.length));
  	if (count != le32_to_cpu(img.header.length)) {
50827a599   Ian Campbell   sunxi: non-FEL SP...
176
177
178
179
180
181
182
183
184
  		perror("Writing output");
  		return EXIT_FAILURE;
  	}
  
  	close(fd_in);
  	close(fd_out);
  
  	return EXIT_SUCCESS;
  }