blob: f866ad5aa538546bb12896f182505fd48db5d30a [file] [log] [blame]
Stephen Warren4b0e5d02012-11-28 11:44:50 -07001/*
Vince Hsu456b8aa2014-07-16 10:37:16 +08002 * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
Stephen Warren4b0e5d02012-11-28 11:44:50 -07003 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Peer Chen8d782ee2011-01-18 21:34:18 -050015 *
16 * See file CREDITS for list of people who contributed to this
17 * project.
Peer Chen8d782ee2011-01-18 21:34:18 -050018 */
19
20/*
21 * parse.c - Parsing support for the cbootimage tool
22 */
23
Peer Chen6f2cbc72012-03-13 11:12:39 +080024#include <ctype.h>
Peer Chen8d782ee2011-01-18 21:34:18 -050025#include "parse.h"
26#include "cbootimage.h"
27#include "data_layout.h"
28#include "crypto.h"
29#include "set.h"
30
31/*
32 * Function prototypes
33 *
34 * ParseXXX() parses XXX in the input
35 * SetXXX() sets state based on the parsing results but does not perform
36 * any parsing of its own
37 * A ParseXXX() function may call other parse functions and set functions.
38 * A SetXXX() function may not call any parseing functions.
39 */
40
Peer Chen6f2cbc72012-03-13 11:12:39 +080041static int
42set_array(build_image_context *context,
43 u_int32_t index,
44 parse_token token,
45 u_int32_t value);
46static char *parse_u32(char *str, u_int32_t *val);
47static char *parse_u8(char *str, u_int32_t *val);
Penny Chiu5f0b21a2014-04-11 17:50:42 +080048static char *parse_chipuid(char *str, u_int8_t *val);
Peer Chen6f2cbc72012-03-13 11:12:39 +080049static char *parse_filename(char *str, char *name, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080050static char *parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +080051 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -080052 enum_item *table,
53 u_int32_t *val);
54static char
55*parse_field_name(char *rest, field_item *field_table, field_item **field);
56static char
Anton Staafe517a4f2011-03-14 12:28:06 -070057*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -080058 char *rest,
59 field_item *field,
60 u_int32_t *value);
Peer Chen8d782ee2011-01-18 21:34:18 -050061static int
62parse_array(build_image_context *context, parse_token token, char *rest);
63static int
64parse_bootloader(build_image_context *context, parse_token token, char *rest);
65static int
Vince Hsu456b8aa2014-07-16 10:37:16 +080066parse_mts_image(build_image_context *context, parse_token token, char *rest);
67static int
Peer Chen8d782ee2011-01-18 21:34:18 -050068parse_value_u32(build_image_context *context, parse_token token, char *rest);
69static int
Penny Chiu5f0b21a2014-04-11 17:50:42 +080070parse_value_chipuid(build_image_context *context,
71 parse_token token,
72 char *rest);
73static int
Peer Chen8d782ee2011-01-18 21:34:18 -050074parse_bct_file(build_image_context *context, parse_token token, char *rest);
Peer Chen8d782ee2011-01-18 21:34:18 -050075static char
Peer Chen6f2cbc72012-03-13 11:12:39 +080076*parse_end_state(char *str, char *uname, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080077static int
78parse_dev_param(build_image_context *context, parse_token token, char *rest);
Peer Chen3a834ed2011-03-04 09:30:05 -080079static int
80parse_sdram_param(build_image_context *context, parse_token token, char *rest);
Peer Chen7557d9b2011-02-24 09:29:23 -080081
Peer Chen6f2cbc72012-03-13 11:12:39 +080082static int process_statement(build_image_context *context,
83 char *str,
84 u_int8_t simple_parse);
Peer Chen8d782ee2011-01-18 21:34:18 -050085
Peer Chen6f2cbc72012-03-13 11:12:39 +080086static parse_item parse_simple_items[] =
Peer Chen7557d9b2011-02-24 09:29:23 -080087{
Peer Chen6f2cbc72012-03-13 11:12:39 +080088 { "Bctfile=", token_bct_file, parse_bct_file },
89 { "BootLoader=", token_bootloader, parse_bootloader },
90 { "Redundancy=", token_redundancy, parse_value_u32 },
91 { "Bctcopy=", token_bct_copy, parse_value_u32 },
Vince Hsu456b8aa2014-07-16 10:37:16 +080092 { "MtsPreboot=", token_mts_preboot, parse_mts_image},
93 { "Mts=", token_mts, parse_mts_image},
Peer Chen6f2cbc72012-03-13 11:12:39 +080094 { "Version=", token_version, parse_value_u32 },
Stephen Warrenf13abb02012-05-16 14:56:55 -060095 { "PreBctPadBlocks=", token_pre_bct_pad_blocks, parse_value_u32 },
Peer Chen6f2cbc72012-03-13 11:12:39 +080096 { NULL, 0, NULL } /* Must be last */
Peer Chen7557d9b2011-02-24 09:29:23 -080097};
98
Peer Chen6f2cbc72012-03-13 11:12:39 +080099static parse_item s_top_level_items[] = {
Peer Chen053d5782011-03-03 10:12:58 -0800100 { "Bctfile=", token_bct_file, parse_bct_file },
101 { "Attribute=", token_attribute, parse_value_u32 },
102 { "Attribute[", token_attribute, parse_array },
103 { "PageSize=", token_page_size, parse_value_u32 },
104 { "BlockSize=", token_block_size, parse_value_u32 },
105 { "PartitionSize=", token_partition_size, parse_value_u32 },
106 { "DevType[", token_dev_type, parse_array },
107 { "DeviceParam[", token_dev_param, parse_dev_param },
Peer Chen3a834ed2011-03-04 09:30:05 -0800108 { "SDRAM[", token_sdram, parse_sdram_param },
Peer Chen053d5782011-03-03 10:12:58 -0800109 { "BootLoader=", token_bootloader, parse_bootloader },
110 { "Redundancy=", token_redundancy, parse_value_u32 },
Peer Chen56f40482011-07-27 02:59:41 -0400111 { "Bctcopy=", token_bct_copy, parse_value_u32 },
Vince Hsu456b8aa2014-07-16 10:37:16 +0800112 { "MtsPreboot=", token_mts_preboot, parse_mts_image},
113 { "Mts=", token_mts, parse_mts_image},
Peer Chen053d5782011-03-03 10:12:58 -0800114 { "Version=", token_version, parse_value_u32 },
Stephen Warrenfb4793a2012-05-16 14:38:17 -0600115 { "OdmData=", token_odm_data, parse_value_u32 },
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800116 { "ChipUid=", token_unique_chip_id, parse_value_chipuid },
117 { "JtagCtrl=", token_secure_jtag_control, parse_value_u32 },
Peer Chen8d782ee2011-01-18 21:34:18 -0500118 { NULL, 0, NULL } /* Must be last */
119};
120
121/* Macro to simplify parser code a bit. */
122#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
123
Peer Chen6f2cbc72012-03-13 11:12:39 +0800124/*
125 * Parse the given string and find the u32 dec/hex number.
126 *
127 * @param str String to parse
128 * @param val Returns value that was parsed
129 * @return the remainder of the string after the number was parsed
130 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500131static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800132parse_u32(char *str, u_int32_t *val)
Peer Chen8d782ee2011-01-18 21:34:18 -0500133{
134 u_int32_t value = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800135 u_int32_t digit;
Peer Chen8d782ee2011-01-18 21:34:18 -0500136
Peer Chen6f2cbc72012-03-13 11:12:39 +0800137 while (*str == '0')
138 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500139
Peer Chen6f2cbc72012-03-13 11:12:39 +0800140 if (tolower(*str) == 'x') {
141 str++;
142 while (isxdigit(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500143 value *= 16;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800144 digit = tolower(*str);
145 value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
146 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500147 }
148 } else {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800149 while (*str >= '0' && *str <= '9') {
150 value = value*10 + (*str - '0');
151 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500152 }
153 }
154 *val = value;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800155 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500156}
157
Peer Chen6f2cbc72012-03-13 11:12:39 +0800158/*
159 * Parse the given string and find the u8 dec/hex number.
160 *
161 * @param str String to parse
162 * @param val Returns value that was parsed
163 * @return the remainder of the string after the number was parsed
164 */
165static char *
166parse_u8(char *str, u_int32_t *val)
Peer Chen7557d9b2011-02-24 09:29:23 -0800167{
168 char *retval;
169
Peer Chen6f2cbc72012-03-13 11:12:39 +0800170 retval = parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800171
172 if (*val > 0xff) {
173 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
174 printf(" Parsed value = %d. Remaining text = %s\n",
175 *val, retval);
176 }
177
178 return retval;
179}
180
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800181/*
182 * Parse the given string and transfer to chip uid.
183 *
184 * @param str String to parse
185 * @param chipuid Returns chip uid that was parsed
186 * @return the remainder of the string after the number was parsed
187 */
188static char *
189parse_chipuid(char *str, u_int8_t *chipuid)
190{
191 int byte_index = 0;
192 int paddings = 0;
193 char byte_str[3];
194
195 if (*str++ != '0')
196 return NULL;
197
198 if (*str++ != 'x')
199 return NULL;
200
201 paddings = strlen(str) % 2;
202 byte_index = strlen(str) / 2 + paddings;
203
204 if (byte_index > 16)
205 return NULL;
206
207 memset(chipuid, 0, 16);
208
209 while (*str != '\0' && byte_index > 0) {
210 char *endptr;
211
212 strncpy(byte_str, str, 2 - paddings);
213 byte_str[2 - paddings] = '\0';
214 str += 2 - paddings;
215
216 chipuid[byte_index - 1] = strtoul(byte_str, &endptr, 16);
217 if (*endptr)
218 return NULL;
219
220 byte_index--;
221 paddings = 0;
222 }
223
224 return str;
225}
Peer Chen7557d9b2011-02-24 09:29:23 -0800226
Peer Chen6f2cbc72012-03-13 11:12:39 +0800227/*
228 * Parse the given string and find the file name then
229 * return the rest of the string.
230 *
231 * @param str String to parse
232 * @param name Returns the filename that was parsed
233 * @param chars_remaining The maximum length of filename
234 * @return the remainder of the string after the name was parsed
235 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500236static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800237parse_filename(char *str, char *name, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500238{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800239 /*
240 * Check if the filename buffer is out of space, preserving one
241 * character to null terminate the string.
242 */
243 while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
244
Peer Chen8d782ee2011-01-18 21:34:18 -0500245 chars_remaining--;
246
247 if (chars_remaining < 1)
248 return NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800249 *name++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500250 }
251
252 /* Null terminate the filename. */
253 *name = '\0';
254
Peer Chen6f2cbc72012-03-13 11:12:39 +0800255 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500256}
257
Peer Chen6f2cbc72012-03-13 11:12:39 +0800258/*
259 * Parse the given string and find the match field name listed
260 * in field table.
261 *
262 * @param rest String to parse
263 * @param field_table The field table to parse
264 * @param field Returns the field item that was parsed
265 * @return NULL or the remainder of the string after the field item was parsed
266 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800267static char
268*parse_field_name(char *rest, field_item *field_table, field_item **field)
269{
270 u_int32_t i;
271 u_int32_t field_name_len = 0;
272
273 assert(field_table != NULL);
274 assert(rest != NULL);
275 assert(field != NULL);
276
Peer Chen6f2cbc72012-03-13 11:12:39 +0800277 while (rest[field_name_len] != '=')
Peer Chen7557d9b2011-02-24 09:29:23 -0800278 field_name_len++;
279
280 /* Parse the field name. */
281 for (i = 0; field_table[i].name != NULL; i++) {
282 if ((strlen(field_table[i].name) == field_name_len) &&
283 !strncmp(field_table[i].name,
284 rest,
285 field_name_len)) {
286
287 *field = &(field_table[i]);
288 rest = rest + field_name_len;
289 return rest;
290 }
291 }
292
293 /* Field wasn't found or a parse error occurred. */
294 return NULL;
295}
296
Peer Chen6f2cbc72012-03-13 11:12:39 +0800297/*
298 * Parse the value based on the field table
299 *
300 * @param context The main context pointer
301 * @param rest String to parse
302 * @param field Field item to parse
303 * @param value Returns the value that was parsed
304 * @return the remainder of the string after the value was parsed
305 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800306static char
Peer Chen6f2cbc72012-03-13 11:12:39 +0800307*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -0800308 char *rest,
309 field_item *field,
310 u_int32_t *value)
311{
312 assert(rest != NULL);
313 assert(field != NULL);
314 assert((field->type != field_type_enum)
315 || (field->enum_table != NULL));
316
317 switch (field->type) {
318 case field_type_enum:
319 rest = parse_enum(context, rest, field->enum_table, value);
320 break;
321
322 case field_type_u32:
323 rest = parse_u32(rest, value);
324 break;
325
326 case field_type_u8:
327 rest = parse_u8(rest, value);
328 break;
329
330 default:
331 printf("Unexpected field type %d at line %d\n",
332 field->type, __LINE__);
333 rest = NULL;
334 break;
335 }
336
337 return rest;
338}
339
Peer Chen6f2cbc72012-03-13 11:12:39 +0800340/*
341 * Parse the given string and find the match enum item listed
342 * in table.
343 *
344 * @param context The main context pointer
345 * @param str String to parse
346 * @param table Enum item table to parse
347 * @param value Returns the value that was parsed
348 * @return the remainder of the string after the item was parsed
349 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800350static char *
351parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800352 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800353 enum_item *table,
354 u_int32_t *val)
355{
356 int i;
357 char *rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800358
359 for (i = 0; table[i].name != NULL; i++) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800360 if (!strncmp(table[i].name, str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800361 strlen(table[i].name))) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800362 *val = table[i].value;
363 rest = str + strlen(table[i].name);
364 return rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800365 }
366 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800367 return parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800368
369}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800370
Peer Chen8d782ee2011-01-18 21:34:18 -0500371/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800372 * Parse the given string and find the bootloader file name, load address and
373 * entry point information then call set_bootloader function.
374 *
375 * @param context The main context pointer
376 * @param token The parse token value
377 * @param rest String to parse
378 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500379 */
380static int parse_bootloader(build_image_context *context,
381 parse_token token,
382 char *rest)
383{
384 char filename[MAX_BUFFER];
385 char e_state[MAX_STR_LEN];
386 u_int32_t load_addr;
387 u_int32_t entry_point;
388
389 assert(context != NULL);
390 assert(rest != NULL);
391
Peer Chen7557d9b2011-02-24 09:29:23 -0800392 if (context->generate_bct != 0)
393 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500394 /* Parse the file name. */
395 rest = parse_filename(rest, filename, MAX_BUFFER);
396 if (rest == NULL)
397 return 1;
398
399 PARSE_COMMA(1);
400
401 /* Parse the load address. */
402 rest = parse_u32(rest, &load_addr);
403 if (rest == NULL)
404 return 1;
405
406 PARSE_COMMA(1);
407
408 /* Parse the entry point. */
409 rest = parse_u32(rest, &entry_point);
410 if (rest == NULL)
411 return 1;
412
413 PARSE_COMMA(1);
414
415 /* Parse the end state. */
416 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
417 if (rest == NULL)
418 return 1;
419 if (strncmp(e_state, "Complete", strlen("Complete")))
420 return 1;
421
422 /* Parsing has finished - set the bootloader */
423 return set_bootloader(context, filename, load_addr, entry_point);
424}
425
426/*
Vince Hsu456b8aa2014-07-16 10:37:16 +0800427 * Parse the given string and find the MTS file name, load address and
428 * entry point information then call set_mts_image function.
429 *
430 * @param context The main context pointer
431 * @param token The parse token value
432 * @param rest String to parse
433 * @return 0 and 1 for success and failure
434 */
435static int parse_mts_image(build_image_context *context,
436 parse_token token,
437 char *rest)
438{
439 char filename[MAX_BUFFER];
440 char e_state[MAX_STR_LEN];
441 u_int32_t load_addr;
442 u_int32_t entry_point;
443
444 assert(context != NULL);
445 assert(rest != NULL);
446
447 if (context->generate_bct != 0)
448 return 0;
449 /* Parse the file name. */
450 rest = parse_filename(rest, filename, MAX_BUFFER);
451 if (rest == NULL)
452 return 1;
453
454 PARSE_COMMA(1);
455
456 /* Parse the load address. */
457 rest = parse_u32(rest, &load_addr);
458 if (rest == NULL)
459 return 1;
460
461 PARSE_COMMA(1);
462
463 /* Parse the entry point. */
464 rest = parse_u32(rest, &entry_point);
465 if (rest == NULL)
466 return 1;
467
468 PARSE_COMMA(1);
469
470 /* Parse the end state. */
471 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
472 if (rest == NULL)
473 return 1;
474 if (strncmp(e_state, "Complete", strlen("Complete")))
475 return 1;
476
477 /* Parsing has finished - set the bootloader */
478 return set_mts_image(context, filename, load_addr, entry_point);
479}
480
481/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800482 * Parse the given string and find the array items in config file.
483 *
484 * @param context The main context pointer
485 * @param token The parse token value
486 * @param rest String to parse
487 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500488 */
489static int
490parse_array(build_image_context *context, parse_token token, char *rest)
491{
492 u_int32_t index;
493 u_int32_t value;
494
495 assert(context != NULL);
496 assert(rest != NULL);
497
498 /* Parse the index. */
499 rest = parse_u32(rest, &index);
500 if (rest == NULL)
501 return 1;
502
503 /* Parse the closing bracket. */
504 if (*rest != ']')
505 return 1;
506 rest++;
507
508 /* Parse the equals sign.*/
509 if (*rest != '=')
510 return 1;
511 rest++;
512
513 /* Parse the value based on the field table. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800514 switch (token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800515 case token_attribute:
516 rest = parse_u32(rest, &value);
517 break;
518 case token_dev_type:
Peer Chen6f2cbc72012-03-13 11:12:39 +0800519 rest = parse_enum(context,
520 rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800521 g_soc_config->devtype_table,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800522 &value);
Peer Chen7557d9b2011-02-24 09:29:23 -0800523 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500524
Peer Chen7557d9b2011-02-24 09:29:23 -0800525 default:
526 /* Unknown token */
527 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500528 }
529
530 if (rest == NULL)
531 return 1;
532
533 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800534 return set_array(context, index, token, value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500535}
536
537/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800538 * Call hw interface to set the value for array item in bct such as device
539 * type and bootloader attribute.
540 *
541 * @param context The main context pointer
542 * @param index The index for array
543 * @param token The parse token value
544 * @param value The value to set
545 * @return 0 and -ENODATA for success and failure
546 */
547
548static int
549set_array(build_image_context *context,
550 u_int32_t index,
551 parse_token token,
552 u_int32_t value)
553{
554 int err = 0;
555
556 assert(context != NULL);
557
558 switch (token) {
559 case token_attribute:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800560 err = g_soc_config->setbl_param(index,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800561 token_bl_attribute,
562 &value,
563 context->bct);
564 break;
565 case token_dev_type:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800566 err = g_soc_config->set_dev_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800567 index,
568 token_dev_type,
569 value);
570 break;
571 default:
572 break;
573 }
574 return err;
575}
576
577/*
578 * General handler for setting u_int32_t values in config files.
579 *
580 * @param context The main context pointer
581 * @param token The parse token value
582 * @param rest String to parse
583 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500584 */
585static int parse_value_u32(build_image_context *context,
586 parse_token token,
587 char *rest)
588{
589 u_int32_t value;
590
591 assert(context != NULL);
592 assert(rest != NULL);
593
594 rest = parse_u32(rest, &value);
595 if (rest == NULL)
596 return 1;
597
Penny Chiub81d2192014-04-11 17:50:39 +0800598 return context_set_value(context, token, &value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500599}
600
Peer Chen6f2cbc72012-03-13 11:12:39 +0800601/*
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800602 * General handler for setting chip uid in config files.
603 *
604 * @param context The main context pointer
605 * @param token The parse token value
606 * @param rest String to parse
607 * @return 0 and 1 for success and failure
608 */
609static int parse_value_chipuid(build_image_context *context,
610 parse_token token,
611 char *rest)
612{
613 u_int8_t value[16];
614
615 assert(context != NULL);
616 assert(rest != NULL);
617
618 rest = parse_chipuid(rest, value);
619 if (rest == NULL)
620 return 1;
621
622 return context_set_value(context, token, value);
623}
624
625/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800626 * Parse the given string and find the bct file name.
627 *
628 * @param context The main context pointer
629 * @param token The parse token value
630 * @param rest String to parse
631 * @return 0 and 1 for success and failure
632 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500633static int
634parse_bct_file(build_image_context *context, parse_token token, char *rest)
635{
636 char filename[MAX_BUFFER];
637
638 assert(context != NULL);
639 assert(rest != NULL);
640
641 /* Parse the file name. */
642 rest = parse_filename(rest, filename, MAX_BUFFER);
643 if (rest == NULL)
644 return 1;
645
646 /* Parsing has finished - set the bctfile */
647 context->bct_filename = filename;
648 /* Read the bct file to buffer */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800649 if (read_bct_file(context))
650 return 1;
651
Peer Chen6f2cbc72012-03-13 11:12:39 +0800652 update_context(context);
Peer Chen8d782ee2011-01-18 21:34:18 -0500653 return 0;
654}
655
656static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800657parse_end_state(char *str, char *uname, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500658{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800659 while (isalpha(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500660
Peer Chen6f2cbc72012-03-13 11:12:39 +0800661 *uname++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500662 if (--chars_remaining < 0)
663 return NULL;
664 }
665 *uname = '\0';
Peer Chen6f2cbc72012-03-13 11:12:39 +0800666 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500667}
668
Peer Chen6f2cbc72012-03-13 11:12:39 +0800669/*
670 * Parse the given string and find device parameter listed in device table
671 * and value for this device parameter. If match, call the corresponding
672 * function in the table to set device parameter.
673 *
674 * @param context The main context pointer
675 * @param token The parse token value
676 * @param rest String to parse
677 * @return 0 and 1 for success and failure
678 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800679static int
680parse_dev_param(build_image_context *context, parse_token token, char *rest)
681{
682 u_int32_t i;
683 u_int32_t value;
684 field_item *field;
685 u_int32_t index;
686 parse_subfield_item *device_item = NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800687
Peer Chen7557d9b2011-02-24 09:29:23 -0800688 assert(context != NULL);
689 assert(rest != NULL);
690
691 /* Parse the index. */
692 rest = parse_u32(rest, &index);
693 if (rest == NULL)
694 return 1;
695
696 /* Parse the closing bracket. */
697 if (*rest != ']')
698 return 1;
699 rest++;
700
701 /* Parse the following '.' */
702 if (*rest != '.')
703 return 1;
704 rest++;
705
706 /* Parse the device name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800707 for (i = 0; g_soc_config->device_type_table[i].prefix != NULL; i++) {
708 if (!strncmp(g_soc_config->device_type_table[i].prefix,
709 rest, strlen(g_soc_config->device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800710
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800711 device_item = &(g_soc_config->device_type_table[i]);
712 rest = rest + strlen(g_soc_config->device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800713
714 /* Parse the field name. */
715 rest = parse_field_name(rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800716 g_soc_config->device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800717 &field);
718 if (rest == NULL)
719 return 1;
720
721 /* Parse the equals sign.*/
722 if (*rest != '=')
723 return 1;
724 rest++;
725
726 /* Parse the value based on the field table. */
727 rest = parse_field_value(context, rest, field, &value);
728 if (rest == NULL)
729 return 1;
730 return device_item->process(context,
731 index, field->token, value);
732 }
733 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800734 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800735}
Peer Chen3a834ed2011-03-04 09:30:05 -0800736
Peer Chen6f2cbc72012-03-13 11:12:39 +0800737/*
738 * Parse the given string and find sdram parameter and value in config
739 * file. If match, call the corresponding function set the sdram parameter.
740 *
741 * @param context The main context pointer
742 * @param token The parse token value
743 * @param rest String to parse
744 * @return 0 and 1 for success and failure
745 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800746static int
747parse_sdram_param(build_image_context *context, parse_token token, char *rest)
748{
749 u_int32_t value;
750 field_item *field;
751 u_int32_t index;
752
753 assert(context != NULL);
754 assert(rest != NULL);
755
756 /* Parse the index. */
757 rest = parse_u32(rest, &index);
758 if (rest == NULL)
759 return 1;
760
761 /* Parse the closing bracket. */
762 if (*rest != ']')
763 return 1;
764 rest++;
765
766 /* Parse the following '.' */
767 if (*rest != '.')
768 return 1;
769 rest++;
770
771 /* Parse the field name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800772 rest = parse_field_name(rest, g_soc_config->sdram_field_table, &field);
773
Peer Chen3a834ed2011-03-04 09:30:05 -0800774 if (rest == NULL)
775 return 1;
776
777 /* Parse the equals sign.*/
778 if (*rest != '=')
779 return 1;
780 rest++;
781
782 /* Parse the value based on the field table. */
783 rest = parse_field_value(context, rest, field, &value);
784 if (rest == NULL)
785 return 1;
786
787 /* Store the result. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800788 return g_soc_config->set_sdram_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800789 index,
790 field->token,
791 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800792}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800793
794/*
795 * Compare the given string with item listed in table.
796 * Execute the proper process function if match.
797 *
798 * @param context The main context pointer
799 * @param str String to parse
800 * @param simple_parse Simple parse flag
801 * @return 0 and 1 for success and failure
802 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500803static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800804process_statement(build_image_context *context,
805 char *str,
806 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500807{
808 int i;
809 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800810 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500811
Peer Chen6f2cbc72012-03-13 11:12:39 +0800812 if (simple_parse == 0)
813 cfg_parse_item = s_top_level_items;
814 else
815 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500816
Peer Chen6f2cbc72012-03-13 11:12:39 +0800817 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
818 if (!strncmp(cfg_parse_item[i].prefix, str,
819 strlen(cfg_parse_item[i].prefix))) {
820 rest = str + strlen(cfg_parse_item[i].prefix);
821
822 return cfg_parse_item[i].process(context,
823 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500824 rest);
825 }
826 }
827
828 /* If this point was reached, there was a processing error. */
829 return 1;
830}
831
Peer Chen6f2cbc72012-03-13 11:12:39 +0800832/*
833 * The main function parse the config file.
834 *
835 * @param context The main context pointer
836 * @param simple_parse Simple parse flag
837 */
838void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500839{
840 char buffer[MAX_BUFFER];
841 int space = 0;
Stephen Warrenacbfad42013-01-17 14:41:28 -0700842 int current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800843 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500844 u_int8_t comment = 0;
845 u_int8_t string = 0;
846 u_int8_t equal_encounter = 0;
847
848 assert(context != NULL);
849 assert(context->config_file != NULL);
850
Peer Chen6f2cbc72012-03-13 11:12:39 +0800851 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500852 if (space >= (MAX_BUFFER-1)) {
853 /* if we exceeded the max buffer size, it is likely
854 due to a missing semi-colon at the end of a line */
855 printf("Config file parsing error!");
856 exit(1);
857 }
858
859 /* Handle failure to complete "//" comment token.
860 Insert the '/' into the busffer and proceed with
861 processing the current character. */
862 if (c_eol_comment_start && current != '/') {
863 c_eol_comment_start = 0;
864 buffer[space++] = '/';
865 }
866
867 switch (current) {
868 case '\"': /* " indicates start or end of a string */
869 if (!comment) {
870 string ^= 1;
871 buffer[space++] = current;
872 }
873 break;
874 case ';':
875 if (!string && !comment) {
876 buffer[space++] = '\0';
877
Peer Chen6f2cbc72012-03-13 11:12:39 +0800878 if (process_statement(context,
879 buffer,
880 simple_parse))
881 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500882 space = 0;
883 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800884 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500885 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500886 break;
887
888 case '/':
889 if (!string && !comment) {
890 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800891 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500892 comment = 1;
893 c_eol_comment_start = 0;
894 } else {
895 /* Potential start of eol comment. */
896 c_eol_comment_start = 1;
897 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800898 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500899 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500900 break;
901
902 /* ignore whitespace. uses fallthrough */
903 case '\n':
904 case '\r': /* carriage returns end comments */
905 string = 0;
906 comment = 0;
907 c_eol_comment_start = 0;
908 case ' ':
909 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800910 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500911 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500912 break;
913
914 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800915 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500916 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800917 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500918 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500919 break;
920
921 default:
922 if (!comment) {
923 buffer[space++] = current;
924 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800925 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500926 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800927 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500928 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500929 }
930 }
931 break;
932 }
933 }
934
935 return;
936
937 error:
938 printf("Error parsing: %s\n", buffer);
939 exit(1);
940}