summaryrefslogtreecommitdiff
path: root/utils/sbtools
diff options
context:
space:
mode:
Diffstat (limited to 'utils/sbtools')
-rw-r--r--utils/sbtools/elftosb.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c
new file mode 100644
index 0000000000..73768dd9a3
--- /dev/null
+++ b/utils/sbtools/elftosb.c
@@ -0,0 +1,472 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define _ISOC99_SOURCE
23#include <stdio.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <inttypes.h>
31#include <string.h>
32#include <ctype.h>
33#include <time.h>
34
35#include "crypto.h"
36#include "elf.h"
37#include "sb.h"
38
39#define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
40#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
41
42void *xmalloc(size_t s) /* malloc helper, used in elf.c */
43{
44 void * r = malloc(s);
45 if(!r) bugp("malloc");
46 return r;
47}
48
49static int convxdigit(char digit, byte *val)
50{
51 if(digit >= '0' && digit <= '9')
52 {
53 *val = digit - '0';
54 return 0;
55 }
56 else if(digit >= 'A' && digit <= 'F')
57 {
58 *val = digit - 'A' + 10;
59 return 0;
60 }
61 else if(digit >= 'a' && digit <= 'f')
62 {
63 *val = digit - 'a' + 10;
64 return 0;
65 }
66 else
67 return 1;
68}
69
70typedef byte (*key_array_t)[16];
71
72static key_array_t read_keys(const char *key_file, int *num_keys)
73{
74 int size;
75 struct stat st;
76 int fd = open(key_file,O_RDONLY);
77 if(fd == -1)
78 bugp("opening key file failed");
79 if(fstat(fd,&st) == -1)
80 bugp("key file stat() failed");
81 size = st.st_size;
82 char *buf = xmalloc(size);
83 if(read(fd, buf, size) != (ssize_t)size)
84 bugp("reading key file");
85 close(fd);
86
87 *num_keys = size ? 1 : 0;
88 char *ptr = buf;
89 /* allow trailing newline at the end (but no space after it) */
90 while(ptr != buf + size && (ptr + 1) != buf + size)
91 {
92 if(*ptr++ == '\n')
93 (*num_keys)++;
94 }
95
96 key_array_t keys = xmalloc(sizeof(byte[16]) * *num_keys);
97 int pos = 0;
98 for(int i = 0; i < *num_keys; i++)
99 {
100 /* skip ws */
101 while(pos < size && isspace(buf[pos]))
102 pos++;
103 /* enough space ? */
104 if((pos + 32) > size)
105 bugp("invalid key file");
106 for(int j = 0; j < 16; j++)
107 {
108 byte a, b;
109 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
110 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
111 keys[i][j] = (a << 4) | b;
112 }
113 pos += 32;
114 }
115 free(buf);
116
117 return keys;
118}
119
120struct cmd_source_t
121{
122 char *identifier;
123 char *filename;
124 struct cmd_source_t *next;
125};
126
127enum cmd_inst_type_t
128{
129 CMD_LOAD,
130 CMD_JUMP,
131 CMD_CALL
132};
133
134struct cmd_inst_t
135{
136 enum cmd_inst_type_t type;
137 char *identifier;
138 struct cmd_inst_t *next;
139};
140
141struct cmd_section_t
142{
143 uint32_t identifier;
144 struct cmd_inst_t *inst_list;
145};
146
147struct cmd_file_t
148{
149 struct cmd_source_t *source_list;
150 struct cmd_section_t *section_list;
151};
152
153enum lexem_type_t
154{
155 LEX_IDENTIFIER,
156 LEX_LPAREN,
157 LEX_RPAREN,
158 LEX_NUMBER,
159 LEX_STRING, /* double-quoted string */
160 LEX_EQUAL,
161 LEX_SEMICOLON,
162 LEX_LBRACE,
163 LEX_RBRACE,
164 LEX_EOF
165};
166
167struct lexem_t
168{
169 enum lexem_type_t type;
170 char *str;
171 uint32_t num;
172};
173
174void __parse_string(char **ptr, char *end, void *user, void (*emit_fn)(void *user, char c))
175{
176 while(*ptr != end)
177 {
178 if(**ptr == '"')
179 break;
180 else if(**ptr == '\\')
181 {
182 (*ptr)++;
183 if(*ptr == end)
184 bug("Unfinished string");
185 if(**ptr == '\\') emit_fn(user, '\\');
186 else if(**ptr == '\'') emit_fn(user, '\'');
187 else if(**ptr == '\"') emit_fn(user, '\"');
188 else bug("Unknown escape sequence \\%c", **ptr);
189 (*ptr)++;
190 }
191 else
192 emit_fn(user, *(*ptr)++);
193 }
194 if(*ptr == end || **ptr != '"')
195 bug("unfinished string");
196 (*ptr)++;
197}
198
199void __parse_string_emit(void *user, char c)
200{
201 char **pstr = (char **)user;
202 *(*pstr)++ = c;
203}
204
205void __parse_string_count(void *user, char c)
206{
207 (void) c;
208 (*(int *)user)++;
209}
210
211void parse_string(char **ptr, char *end, struct lexem_t *lexem)
212{
213 /* skip " */
214 (*ptr)++;
215 char *p = *ptr;
216 /* compute length */
217 int length = 0;
218 __parse_string(&p, end, (void *)&length, __parse_string_count);
219 /* parse again */
220 lexem->type = LEX_STRING;
221 lexem->str = xmalloc(length + 1);
222 lexem->str[length] = 0;
223 char *pstr = lexem->str;
224 __parse_string(ptr, end, (void *)&pstr, __parse_string_emit);
225}
226
227void parse_number(char **ptr, char *end, struct lexem_t *lexem)
228{
229 int base = 10;
230 if(**ptr == '0' && (*ptr) + 1 != end && (*ptr)[1] == 'x')
231 {
232 (*ptr) += 2;
233 base = 16;
234 }
235
236 lexem->type = LEX_NUMBER;
237 lexem->num = 0;
238 while(*ptr != end && isxdigit(**ptr))
239 {
240 if(base == 10 && !isdigit(**ptr))
241 break;
242 byte v;
243 if(convxdigit(**ptr, &v))
244 break;
245 lexem->num = base * lexem->num + v;
246 (*ptr)++;
247 }
248}
249
250void parse_identifier(char **ptr, char *end, struct lexem_t *lexem)
251{
252 /* remember position */
253 char *old = *ptr;
254 while(*ptr != end && (isalnum(**ptr) || **ptr == '_'))
255 (*ptr)++;
256 lexem->type = LEX_IDENTIFIER;
257 int len = *ptr - old;
258 lexem->str = xmalloc(len + 1);
259 lexem->str[len] = 0;
260 memcpy(lexem->str, old, len);
261}
262
263void next_lexem(char **ptr, char *end, struct lexem_t *lexem)
264{
265 #define ret_simple(t, advance) ({(*ptr) += advance; lexem->type = t; return;})
266 while(true)
267 {
268 /* skip whitespace */
269 if(**ptr == ' ' || **ptr == '\t' || **ptr == '\n' || **ptr == '\r')
270 {
271 (*ptr)++;
272 continue;
273 }
274 /* skip comments */
275 if(**ptr == '/' && (*ptr) + 1 != end && (*ptr)[1] == '/')
276 {
277 while(*ptr != end && **ptr != '\n')
278 (*ptr)++;
279 continue;
280 }
281 break;
282 }
283 if(*ptr == end) ret_simple(LEX_EOF, 0);
284 if(**ptr == '(') ret_simple(LEX_LPAREN, 1);
285 if(**ptr == ')') ret_simple(LEX_RPAREN, 1);
286 if(**ptr == '{') ret_simple(LEX_LBRACE, 1);
287 if(**ptr == '}') ret_simple(LEX_RBRACE, 1);
288 if(**ptr == '=') ret_simple(LEX_EQUAL, 1);
289 if(**ptr == ';') ret_simple(LEX_SEMICOLON, 1);
290 if(**ptr == '"') return parse_string(ptr, end, lexem);
291 if(isdigit(**ptr)) return parse_number(ptr, end, lexem);
292 if(isalpha(**ptr) || **ptr == '_') return parse_identifier(ptr, end, lexem);
293 bug("Unexpected character '%c' in command file\n", **ptr);
294 #undef ret_simple
295}
296
297void log_lexem(struct lexem_t *lexem)
298{
299 switch(lexem->type)
300 {
301 case LEX_EOF: printf("<eof>"); break;
302 case LEX_EQUAL: printf("="); break;
303 case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break;
304 case LEX_LPAREN: printf("("); break;
305 case LEX_RPAREN: printf(")"); break;
306 case LEX_LBRACE: printf("{"); break;
307 case LEX_RBRACE: printf("}"); break;
308 case LEX_SEMICOLON: printf(";"); break;
309 case LEX_NUMBER: printf("num(%d)", lexem->num); break;
310 case LEX_STRING: printf("str(%s)", lexem->str); break;
311 default: printf("<unk>");
312 }
313}
314
315char *find_source_by_id(struct cmd_file_t *cmd_file, const char *id)
316{
317 struct cmd_source_t *src = cmd_file->source_list;
318 while(src)
319 {
320 if(strcmp(src->identifier, id) == 0)
321 return src->filename;
322 src = src->next;
323 }
324 return NULL;
325}
326
327struct cmd_file_t *read_command_file(const char *file)
328{
329 int size;
330 struct stat st;
331 int fd = open(file,O_RDONLY);
332 if(fd == -1)
333 bugp("opening command file failed");
334 if(fstat(fd,&st) == -1)
335 bugp("command file stat() failed");
336 size = st.st_size;
337 char *buf = xmalloc(size);
338 if(read(fd, buf, size) != (ssize_t)size)
339 bugp("reading command file");
340 close(fd);
341
342 struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t));
343 memset(cmd_file, 0, sizeof(struct cmd_file_t));
344
345 struct lexem_t lexem;
346 char *p = buf;
347 char *end = buf + size;
348 #define next() next_lexem(&p, end, &lexem)
349 /* sources */
350 next();
351 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources") != 0)
352 bug("invalid command file: 'sources' expected");
353 next();
354 if(lexem.type != LEX_LBRACE)
355 bug("invalid command file: '{' expected after 'sources'");
356
357 while(true)
358 {
359 next();
360 if(lexem.type == LEX_RBRACE)
361 break;
362 struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
363 src->next = cmd_file->source_list;
364 if(lexem.type != LEX_IDENTIFIER)
365 bug("invalid command file: identifier expected in sources");
366 src->identifier = lexem.str;
367 next();
368 if(lexem.type != LEX_EQUAL)
369 bug("invalid command file: '=' expected after identifier");
370 next();
371 if(lexem.type != LEX_STRING)
372 bug("invalid command file: string expected after '='");
373 src->filename = lexem.str;
374 next();
375 if(lexem.type != LEX_SEMICOLON)
376 bug("invalid command file: ';' expected after string");
377 if(find_source_by_id(cmd_file, src->identifier) != NULL)
378 bug("invalid command file: duplicated source identifier");
379 cmd_file->source_list = src;
380 }
381
382 /* sections */
383 while(true)
384 {
385 struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
386 struct cmd_inst_t *end_list = NULL;
387 memset(sec, 0, sizeof(struct cmd_section_t));
388 next();
389 if(lexem.type == LEX_EOF)
390 break;
391 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
392 bug("invalid command file: 'section' expected");
393 next();
394 if(lexem.type != LEX_LPAREN)
395 bug("invalid command file: '(' expected after 'section'");
396 next();
397 if(lexem.type != LEX_NUMBER)
398 bug("invalid command file: number expected as section identifier");
399 sec->identifier = lexem.num;
400 next();
401 if(lexem.type != LEX_RPAREN)
402 bug("invalid command file: ')' expected after section identifier");
403 next();
404 if(lexem.type != LEX_LBRACE)
405 bug("invalid command file: '{' expected after section directive");
406 /* commands */
407 while(true)
408 {
409 struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
410 memset(inst, 0, sizeof(struct cmd_inst_t));
411 next();
412 if(lexem.type == LEX_RBRACE)
413 break;
414 if(lexem.type != LEX_IDENTIFIER)
415 bug("invalid command file: instruction expected in section");
416 if(strcmp(lexem.str, "load") == 0)
417 inst->type = CMD_LOAD;
418 else if(strcmp(lexem.str, "call") == 0)
419 inst->type = CMD_CALL;
420 else if(strcmp(lexem.str, "jump") == 0)
421 inst->type = CMD_JUMP;
422 else
423 bug("invalid command file: instruction expected in section");
424 next();
425 if(lexem.type != LEX_IDENTIFIER)
426 bug("invalid command file: identifier expected after instruction");
427 inst->identifier = lexem.str;
428 if(find_source_by_id(cmd_file, inst->identifier) == NULL)
429 bug("invalid command file: undefined reference to source '%s'", inst->identifier);
430 next();
431 if(lexem.type != LEX_SEMICOLON)
432 bug("invalid command file: expected ';' after command");
433
434 if(end_list == NULL)
435 {
436 sec->inst_list = inst;
437 end_list = inst;
438 }
439 else
440 {
441 end_list->next = inst;
442 end_list = inst;
443 }
444 }
445 }
446 #undef next
447
448 return cmd_file;
449}
450
451#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
452
453static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
454{
455 uint8_t sum = 90;
456 byte *ptr = (byte *)hdr;
457 for(int i = 1; i < 16; i++)
458 sum += ptr[i];
459 return sum;
460}
461
462int main(int argc, const char **argv)
463{
464 if(argc != 4)
465 bug("Usage: %s <cmd file> <key file> <out file>\n",*argv);
466
467 int nr_keys;
468 key_array_t key_array = read_keys(argv[2], &nr_keys);
469 struct cmd_file_t *cmd_file = read_command_file(argv[1]);
470
471 return 0;
472}