Blame view

tools/mkexynosspl.c 5.11 KB
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
1
2
3
  /*
   * Copyright (C) 2012 Samsung Electronics
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
4
   * SPDX-License-Identifier:	GPL-2.0+
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
5
6
7
8
9
10
11
12
13
14
15
16
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <errno.h>
  #include <string.h>
  #include <sys/stat.h>
  #include <compiler.h>
  
  #define CHECKSUM_OFFSET		(14*1024-4)
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
17
18
19
  #define FILE_PERM		(S_IRUSR | S_IWUSR | S_IRGRP \
  				| S_IWGRP | S_IROTH | S_IWOTH)
  /*
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   * Requirement for the fixed size SPL header:
   * IROM code reads first (CHECKSUM_OFFSET + 4) bytes from boot device. It then
   * calculates the checksum of CHECKSUM_OFFSET bytes and compares with data at
   * CHECKSUM_OFFSET location.
   *
   * Requirement for the variable size SPL header:
  
   * IROM code reads the below header to find out the size of the blob (total
   * size, header size included) and its checksum. Then it reads the rest of the
   * blob [i.e size - sizeof(struct var_size_header) bytes], calculates the
   * checksum and compares it with value read from the header.
   */
  struct var_size_header {
  	uint32_t spl_size;
  	uint32_t spl_checksum;
  	uint32_t reserved[2];
  };
  
  static const char *prog_name;
  
  static void write_to_file(int ofd, void *buffer, int size)
  {
  	if (write(ofd, buffer, size) == size)
  		return;
  
  	fprintf(stderr, "%s: Failed to write to output file: %s
  ",
  		prog_name, strerror(errno));
  	exit(EXIT_FAILURE);
  }
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
50

0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  /*
   * The argv is expected to include one optional parameter and two filenames:
   * [--vs] IN OUT
   *
   * --vs - turns on the variable size SPL mode
   * IN  - the u-boot SPL binary, usually u-boot-spl.bin
   * OUT - the prepared SPL blob, usually ${BOARD}-spl.bin
   *
   * This utility first reads the "u-boot-spl.bin" into a buffer. In case of
   * fixed size SPL the buffer size is exactly CHECKSUM_OFFSET (such that
   * smaller u-boot-spl.bin gets padded with 0xff bytes, the larger than limit
   * u-boot-spl.bin causes an error). For variable size SPL the buffer size is
   * eqaul to size of the IN file.
   *
   * Then it calculates checksum of the buffer by just summing up all bytes.
   * Then
   *
   * - for fixed size SPL the buffer is written into the output file and the
   *   checksum is appended to the file in little endian format, which results
   *   in checksum added exactly at CHECKSUM_OFFSET.
   *
   * - for variable size SPL the checksum and file size are stored in the
   *   var_size_header structure (again, in little endian format) and the
   *   structure is written into the output file. Then the buffer is written
   *   into the output file.
   */
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
77
78
  int main(int argc, char **argv)
  {
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
79
  	unsigned char *buffer;
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
80
81
82
  	int i, ifd, ofd;
  	uint32_t checksum = 0;
  	off_t	len;
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
83
  	int	var_size_flag, read_size, count;
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
84
  	struct stat stat;
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	const int if_index = argc - 2; /* Input file name index in argv. */
  	const int of_index = argc - 1; /* Output file name index in argv. */
  
  	/* Strip path off the program name. */
  	prog_name = strrchr(argv[0], '/');
  	if (prog_name)
  		prog_name++;
  	else
  		prog_name = argv[0];
  
  	if ((argc < 3) ||
  	    (argc > 4) ||
  	    ((argc == 4) && strcmp(argv[1], "--vs"))) {
  		fprintf(stderr, "Usage: %s [--vs] <infile> <outfile>
  ",
  			prog_name);
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
101
102
  		exit(EXIT_FAILURE);
  	}
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
103
104
105
106
  	/* four args mean variable size SPL wrapper is required */
  	var_size_flag = (argc == 4);
  
  	ifd = open(argv[if_index], O_RDONLY);
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
107
108
109
  	if (ifd < 0) {
  		fprintf(stderr, "%s: Can't open %s: %s
  ",
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
110
  			prog_name, argv[if_index], strerror(errno));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
111
112
  		exit(EXIT_FAILURE);
  	}
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
113
  	ofd = open(argv[of_index], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
310ae37ed   Thomas Huth   Fix bad return va...
114
  	if (ofd < 0) {
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
115
116
  		fprintf(stderr, "%s: Can't open %s: %s
  ",
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
117
  			prog_name, argv[of_index], strerror(errno));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
118
119
120
121
122
123
  		exit(EXIT_FAILURE);
  	}
  
  	if (fstat(ifd, &stat)) {
  		fprintf(stderr, "%s: Unable to get size of %s: %s
  ",
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
124
  			prog_name, argv[if_index], strerror(errno));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
125
126
127
128
  		exit(EXIT_FAILURE);
  	}
  
  	len = stat.st_size;
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	if (var_size_flag) {
  		read_size = len;
  		count = len;
  	} else {
  		if (len > CHECKSUM_OFFSET) {
  			fprintf(stderr,
  				"%s: %s is too big (exceeds %d bytes)
  ",
  				prog_name, argv[if_index], CHECKSUM_OFFSET);
  			exit(EXIT_FAILURE);
  		}
  		count = CHECKSUM_OFFSET;
  		read_size = len;
  	}
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
143

0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
144
145
146
147
148
149
150
151
  	buffer = malloc(count);
  	if (!buffer) {
  		fprintf(stderr,
  			"%s: Failed to allocate %d bytes to store %s
  ",
  			prog_name, count, argv[if_index]);
  		exit(EXIT_FAILURE);
  	}
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
152

0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
153
154
155
156
  	if (read(ifd, buffer, read_size) != read_size) {
  		fprintf(stderr, "%s: Can't read %s: %s
  ",
  			prog_name, argv[if_index], strerror(errno));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
157
158
  		exit(EXIT_FAILURE);
  	}
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
159
160
161
  	/* Pad if needed with 0xff to make flashing faster. */
  	if (read_size < count)
  		memset((char *)buffer + read_size, 0xff, count - read_size);
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
162

0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
163
164
  	for (i = 0, checksum = 0; i < count; i++)
  		checksum += buffer[i];
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
165
  	checksum = cpu_to_le32(checksum);
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
166
167
168
169
  	if (var_size_flag) {
  		/* Prepare and write out the variable size SPL header. */
  		struct var_size_header vsh;
  		uint32_t spl_size;
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
170

0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
171
172
  		memset(&vsh, 0, sizeof(vsh));
  		memcpy(&vsh.spl_checksum, &checksum, sizeof(checksum));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
173

0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
174
175
176
  		spl_size = cpu_to_le32(count + sizeof(struct var_size_header));
  		memcpy(&vsh.spl_size, &spl_size, sizeof(spl_size));
  		write_to_file(ofd, &vsh, sizeof(vsh));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
177
  	}
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
178
179
180
181
182
  	write_to_file(ofd, buffer, count);
  
  	/* For fixed size SPL checksum is appended in the end. */
  	if (!var_size_flag)
  		write_to_file(ofd, &checksum, sizeof(checksum));
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
183
184
  	close(ifd);
  	close(ofd);
0fcac1abd   Rajeshwari Birje   SPL: EXYNOS: Prep...
185
  	free(buffer);
81e352032   Chander Kashyap   EXYNOS: SMDK5250:...
186
187
188
  
  	return EXIT_SUCCESS;
  }