13 #define VALIDATION_WORD 0x31305341
15 #define BRANCH_INST 0xea /* ARM opcode for "b" (unconditional branch) */
17 #define MAX_V0IMAGE_SIZE (60 * 1024 - 4)
18 /* Max size without authentication is 224 KB, due to memory used by
19 * the ROM boot code as a workspace out of the 256 KB of OCRAM */
20 #define MAX_V1IMAGE_SIZE (224 * 1024 - 4)
22 static int add_barebox_header
;
24 struct socfpga_header
{
25 uint8_t validation_word
[4];
30 uint8_t program_length
[2];
33 uint8_t start_vector
[4];
36 uint8_t header_length
[2];
37 uint8_t program_length
[4];
38 uint8_t entry_offset
[4];
45 static uint32_t bb_header
[] = {
46 0xea00007e, /* b 0x200 */
47 0xeafffffe, /* 1: b 1b */
48 0xeafffffe, /* 1: b 1b */
49 0xeafffffe, /* 1: b 1b */
50 0xeafffffe, /* 1: b 1b */
51 0xeafffffe, /* 1: b 1b */
52 0xeafffffe, /* 1: b 1b */
53 0xeafffffe, /* 1: b 1b */
54 0x65726162, /* 'bare' */
55 0x00786f62, /* 'box\0' */
56 0x00000000, /* padding */
57 0x00000000, /* padding */
58 0x00000000, /* padding */
59 0x00000000, /* padding */
60 0x00000000, /* padding */
61 0x00000000, /* padding */
62 0x00000000, /* socfpga header */
63 0x00000000, /* socfpga header */
64 0x00000000, /* socfpga header */
65 0xea00006b, /* entry. b 0x200 (offset may be adjusted) */
68 static int read_full(int fd
, void *buf
, size_t size
)
75 now
= read(fd
, buf
, size
);
88 static int write_full(int fd
, void *buf
, size_t size
)
94 now
= write(fd
, buf
, size
);
104 static const uint32_t crc_table
[256] = {
105 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
106 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
107 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
108 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
109 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
110 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
111 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
112 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
113 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
114 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
115 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
116 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
117 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
118 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
119 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
120 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
121 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
122 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
123 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
124 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
125 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
126 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
127 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
128 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
129 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
130 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
131 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
132 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
133 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
134 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
135 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
136 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
137 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
138 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
139 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
140 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
141 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
142 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
143 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
144 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
145 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
146 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
147 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
150 uint32_t crc32(uint32_t crc
, void *_buf
, int length
)
155 crc
= crc
<< 8 ^ crc_table
[(crc
>> 24 ^ *(buf
++)) & 0xff];
160 /* Create an ARM relative branch instuction
161 * branch is where the instruction will be placed and dest points to where
162 * it should branch too. */
163 static void branch(uint8_t *branch
, uint8_t *dest
)
165 int offset
= dest
- branch
- 8; /* PC is offset +8 bytes on ARM */
167 branch
[0] = (offset
>> 2) & 0xff; /* instruction uses offset/4 */
168 branch
[1] = (offset
>> 10) & 0xff;
169 branch
[2] = (offset
>> 18) & 0xff;
170 branch
[3] = BRANCH_INST
;
173 /* start_addr is where the socfpga header's start instruction should branch to.
174 * It should be relative to the start of buf */
175 static int add_socfpga_header(void *buf
, size_t size
, unsigned start_addr
, unsigned version
)
177 struct socfpga_header
*header
= buf
+ 0x40;
179 uint8_t *bufp
, *sumendp
;
184 fprintf(stderr
, "%s: size must be multiple of 4\n", __func__
);
188 /* Absolute address of entry point in buf */
189 entry
= buf
+ start_addr
;
191 sumendp
= &header
->v0
.checksum
[0];
193 sumendp
= &header
->v1
.checksum
[0];
195 /* The ROM loader can't handle a negative offset */
196 if (entry
< (void*)header
) {
197 /* add a trampoline branch inst after end of the header */
198 uint8_t *trampoline
= (void*)(header
+ 1);
199 branch(trampoline
, entry
);
201 /* and then make the trampoline the entry point */
204 /* Calculate start address as offset relative to start of header */
205 start_addr
= entry
- (void*)header
;
208 header
->validation_word
[0] = VALIDATION_WORD
& 0xff;
209 header
->validation_word
[1] = (VALIDATION_WORD
>> 8) & 0xff;
210 header
->validation_word
[2] = (VALIDATION_WORD
>> 16) & 0xff;
211 header
->validation_word
[3] = (VALIDATION_WORD
>> 24) & 0xff;
212 header
->version
= version
;
216 header
->v0
.program_length
[0] = (size
>> 2) & 0xff; /* length in words */
217 header
->v0
.program_length
[1] = (size
>> 10) & 0xff;
218 header
->v0
.spare
[0] = 0;
219 header
->v0
.spare
[1] = 0;
220 branch(header
->v0
.start_vector
, entry
);
222 header
->v1
.header_length
[0] = (sizeof(*header
) >> 0) & 0xff;
223 header
->v1
.header_length
[1] = (sizeof(*header
) >> 8) & 0xff;
224 header
->v1
.program_length
[0] = (size
>> 0) & 0xff;
225 header
->v1
.program_length
[1] = (size
>> 8) & 0xff;
226 header
->v1
.program_length
[2] = (size
>> 16) & 0xff;
227 header
->v1
.program_length
[3] = (size
>> 24) & 0xff;
228 header
->v1
.entry_offset
[0] = (start_addr
>> 0) & 0xff;
229 header
->v1
.entry_offset
[1] = (start_addr
>> 8) & 0xff;
230 header
->v1
.entry_offset
[2] = (start_addr
>> 16) & 0xff;
231 header
->v1
.entry_offset
[3] = (start_addr
>> 24) & 0xff;
232 header
->v1
.spare
[0] = 0;
233 header
->v1
.spare
[1] = 0;
236 /* Sum from beginning of header to start of checksum field */
238 for (bufp
= (uint8_t*)header
; bufp
< sumendp
; bufp
++)
242 header
->v0
.checksum
[0] = checksum
& 0xff;;
243 header
->v0
.checksum
[1] = (checksum
>> 8) & 0xff;;
245 header
->v1
.checksum
[0] = checksum
& 0xff;;
246 header
->v1
.checksum
[1] = (checksum
>> 8) & 0xff;;
249 crc
= buf
+ size
- sizeof(uint32_t);
251 *crc
= crc32(0xffffffff, buf
, size
- sizeof(uint32_t));
257 static void usage(const char *prgname
)
259 fprintf(stderr
, "usage: %s [-hb] [-v version] <infile> -o <outfile>\n", prgname
);
262 int main(int argc
, char *argv
[])
265 const char *outfile
= NULL
, *infile
;
269 int max_image_size
, min_image_size
= 80;
270 int addsize
= 0, pad
;
271 unsigned int version
= 0;
273 while ((opt
= getopt(argc
, argv
, "o:hbv:")) != -1) {
276 version
= atoi(optarg
);
278 printf("Versions supported: 0 or 1\n");
284 add_barebox_header
= 1;
300 max_image_size
= MAX_V0IMAGE_SIZE
;
302 max_image_size
= MAX_V1IMAGE_SIZE
;
304 max_image_size
-= addsize
;
306 if (optind
== argc
|| !outfile
) {
310 infile
= argv
[optind
];
312 ret
= stat(infile
, &s
);
318 if (s
.st_size
< min_image_size
) {
319 fprintf(stderr
, "input image too small. Minimum is %d bytes\n",
324 if (s
.st_size
> max_image_size
) {
325 fprintf(stderr
, "input image too big. Maximum is %d bytes, got %ld bytes\n",
326 max_image_size
, s
.st_size
);
330 fd
= open(infile
, O_RDONLY
);
332 perror("open infile");
336 pad
= s
.st_size
& 0x3;
340 buf
= calloc(s
.st_size
+ 4 + addsize
+ pad
, 1);
346 ret
= read_full(fd
, buf
+ addsize
, s
.st_size
);
348 perror("read infile");
354 if (add_barebox_header
) {
355 memcpy(buf
, bb_header
, sizeof(bb_header
));
358 ret
= add_socfpga_header(buf
, s
.st_size
+ 4 + addsize
+ pad
, addsize
,
363 fd
= open(outfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
365 perror("open outfile");
369 ret
= write_full(fd
, buf
, s
.st_size
+ 4 + addsize
+ pad
);
371 perror("write outfile");