blob: 8c98244373935df6414dabf9fadd65d8a8995ea9 [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 },
Jimmy Zhang623a1ad2015-03-20 17:20:19 -0700118 { "DebugCtrl=", token_secure_debug_control, parse_value_u32 },
Peer Chen8d782ee2011-01-18 21:34:18 -0500119 { NULL, 0, NULL } /* Must be last */
120};
121
122/* Macro to simplify parser code a bit. */
123#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
124
Peer Chen6f2cbc72012-03-13 11:12:39 +0800125/*
126 * Parse the given string and find the u32 dec/hex number.
127 *
128 * @param str String to parse
129 * @param val Returns value that was parsed
130 * @return the remainder of the string after the number was parsed
131 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500132static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800133parse_u32(char *str, u_int32_t *val)
Peer Chen8d782ee2011-01-18 21:34:18 -0500134{
135 u_int32_t value = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800136 u_int32_t digit;
Peer Chen8d782ee2011-01-18 21:34:18 -0500137
Peer Chen6f2cbc72012-03-13 11:12:39 +0800138 while (*str == '0')
139 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500140
Peer Chen6f2cbc72012-03-13 11:12:39 +0800141 if (tolower(*str) == 'x') {
142 str++;
143 while (isxdigit(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500144 value *= 16;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800145 digit = tolower(*str);
146 value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
147 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500148 }
149 } else {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800150 while (*str >= '0' && *str <= '9') {
151 value = value*10 + (*str - '0');
152 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500153 }
154 }
155 *val = value;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800156 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500157}
158
Peer Chen6f2cbc72012-03-13 11:12:39 +0800159/*
160 * Parse the given string and find the u8 dec/hex number.
161 *
162 * @param str String to parse
163 * @param val Returns value that was parsed
164 * @return the remainder of the string after the number was parsed
165 */
166static char *
167parse_u8(char *str, u_int32_t *val)
Peer Chen7557d9b2011-02-24 09:29:23 -0800168{
169 char *retval;
170
Peer Chen6f2cbc72012-03-13 11:12:39 +0800171 retval = parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800172
173 if (*val > 0xff) {
174 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
175 printf(" Parsed value = %d. Remaining text = %s\n",
176 *val, retval);
177 }
178
179 return retval;
180}
181
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800182/*
183 * Parse the given string and transfer to chip uid.
184 *
185 * @param str String to parse
186 * @param chipuid Returns chip uid that was parsed
187 * @return the remainder of the string after the number was parsed
188 */
189static char *
190parse_chipuid(char *str, u_int8_t *chipuid)
191{
192 int byte_index = 0;
193 int paddings = 0;
194 char byte_str[3];
195
196 if (*str++ != '0')
197 return NULL;
198
199 if (*str++ != 'x')
200 return NULL;
201
202 paddings = strlen(str) % 2;
203 byte_index = strlen(str) / 2 + paddings;
204
205 if (byte_index > 16)
206 return NULL;
207
208 memset(chipuid, 0, 16);
209
210 while (*str != '\0' && byte_index > 0) {
211 char *endptr;
212
213 strncpy(byte_str, str, 2 - paddings);
214 byte_str[2 - paddings] = '\0';
215 str += 2 - paddings;
216
217 chipuid[byte_index - 1] = strtoul(byte_str, &endptr, 16);
218 if (*endptr)
219 return NULL;
220
221 byte_index--;
222 paddings = 0;
223 }
224
225 return str;
226}
Peer Chen7557d9b2011-02-24 09:29:23 -0800227
Peer Chen6f2cbc72012-03-13 11:12:39 +0800228/*
229 * Parse the given string and find the file name then
230 * return the rest of the string.
231 *
232 * @param str String to parse
233 * @param name Returns the filename that was parsed
234 * @param chars_remaining The maximum length of filename
235 * @return the remainder of the string after the name was parsed
236 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500237static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800238parse_filename(char *str, char *name, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500239{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800240 /*
241 * Check if the filename buffer is out of space, preserving one
242 * character to null terminate the string.
243 */
244 while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
245
Peer Chen8d782ee2011-01-18 21:34:18 -0500246 chars_remaining--;
247
248 if (chars_remaining < 1)
249 return NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800250 *name++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500251 }
252
253 /* Null terminate the filename. */
254 *name = '\0';
255
Peer Chen6f2cbc72012-03-13 11:12:39 +0800256 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500257}
258
Peer Chen6f2cbc72012-03-13 11:12:39 +0800259/*
260 * Parse the given string and find the match field name listed
261 * in field table.
262 *
263 * @param rest String to parse
264 * @param field_table The field table to parse
265 * @param field Returns the field item that was parsed
266 * @return NULL or the remainder of the string after the field item was parsed
267 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800268static char
269*parse_field_name(char *rest, field_item *field_table, field_item **field)
270{
271 u_int32_t i;
272 u_int32_t field_name_len = 0;
273
274 assert(field_table != NULL);
275 assert(rest != NULL);
276 assert(field != NULL);
277
Peer Chen6f2cbc72012-03-13 11:12:39 +0800278 while (rest[field_name_len] != '=')
Peer Chen7557d9b2011-02-24 09:29:23 -0800279 field_name_len++;
280
281 /* Parse the field name. */
282 for (i = 0; field_table[i].name != NULL; i++) {
283 if ((strlen(field_table[i].name) == field_name_len) &&
284 !strncmp(field_table[i].name,
285 rest,
286 field_name_len)) {
287
288 *field = &(field_table[i]);
289 rest = rest + field_name_len;
290 return rest;
291 }
292 }
293
294 /* Field wasn't found or a parse error occurred. */
295 return NULL;
296}
297
Peer Chen6f2cbc72012-03-13 11:12:39 +0800298/*
299 * Parse the value based on the field table
300 *
301 * @param context The main context pointer
302 * @param rest String to parse
303 * @param field Field item to parse
304 * @param value Returns the value that was parsed
305 * @return the remainder of the string after the value was parsed
306 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800307static char
Peer Chen6f2cbc72012-03-13 11:12:39 +0800308*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -0800309 char *rest,
310 field_item *field,
311 u_int32_t *value)
312{
313 assert(rest != NULL);
314 assert(field != NULL);
315 assert((field->type != field_type_enum)
316 || (field->enum_table != NULL));
317
318 switch (field->type) {
319 case field_type_enum:
320 rest = parse_enum(context, rest, field->enum_table, value);
321 break;
322
323 case field_type_u32:
324 rest = parse_u32(rest, value);
325 break;
326
327 case field_type_u8:
328 rest = parse_u8(rest, value);
329 break;
330
331 default:
332 printf("Unexpected field type %d at line %d\n",
333 field->type, __LINE__);
334 rest = NULL;
335 break;
336 }
337
338 return rest;
339}
340
Peer Chen6f2cbc72012-03-13 11:12:39 +0800341/*
342 * Parse the given string and find the match enum item listed
343 * in table.
344 *
345 * @param context The main context pointer
346 * @param str String to parse
347 * @param table Enum item table to parse
348 * @param value Returns the value that was parsed
349 * @return the remainder of the string after the item was parsed
350 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800351static char *
352parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800353 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800354 enum_item *table,
355 u_int32_t *val)
356{
357 int i;
358 char *rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800359
360 for (i = 0; table[i].name != NULL; i++) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800361 if (!strncmp(table[i].name, str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800362 strlen(table[i].name))) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800363 *val = table[i].value;
364 rest = str + strlen(table[i].name);
365 return rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800366 }
367 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800368 return parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800369
370}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800371
Peer Chen8d782ee2011-01-18 21:34:18 -0500372/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800373 * Parse the given string and find the bootloader file name, load address and
374 * entry point information then call set_bootloader function.
375 *
376 * @param context The main context pointer
377 * @param token The parse token value
378 * @param rest String to parse
379 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500380 */
381static int parse_bootloader(build_image_context *context,
382 parse_token token,
383 char *rest)
384{
385 char filename[MAX_BUFFER];
386 char e_state[MAX_STR_LEN];
387 u_int32_t load_addr;
388 u_int32_t entry_point;
389
390 assert(context != NULL);
391 assert(rest != NULL);
392
Peer Chen7557d9b2011-02-24 09:29:23 -0800393 if (context->generate_bct != 0)
394 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500395 /* Parse the file name. */
396 rest = parse_filename(rest, filename, MAX_BUFFER);
397 if (rest == NULL)
398 return 1;
399
400 PARSE_COMMA(1);
401
402 /* Parse the load address. */
403 rest = parse_u32(rest, &load_addr);
404 if (rest == NULL)
405 return 1;
406
407 PARSE_COMMA(1);
408
409 /* Parse the entry point. */
410 rest = parse_u32(rest, &entry_point);
411 if (rest == NULL)
412 return 1;
413
414 PARSE_COMMA(1);
415
416 /* Parse the end state. */
417 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
418 if (rest == NULL)
419 return 1;
420 if (strncmp(e_state, "Complete", strlen("Complete")))
421 return 1;
422
423 /* Parsing has finished - set the bootloader */
424 return set_bootloader(context, filename, load_addr, entry_point);
425}
426
427/*
Vince Hsu456b8aa2014-07-16 10:37:16 +0800428 * Parse the given string and find the MTS file name, load address and
429 * entry point information then call set_mts_image function.
430 *
431 * @param context The main context pointer
432 * @param token The parse token value
433 * @param rest String to parse
434 * @return 0 and 1 for success and failure
435 */
436static int parse_mts_image(build_image_context *context,
437 parse_token token,
438 char *rest)
439{
440 char filename[MAX_BUFFER];
441 char e_state[MAX_STR_LEN];
442 u_int32_t load_addr;
443 u_int32_t entry_point;
444
445 assert(context != NULL);
446 assert(rest != NULL);
447
448 if (context->generate_bct != 0)
449 return 0;
450 /* Parse the file name. */
451 rest = parse_filename(rest, filename, MAX_BUFFER);
452 if (rest == NULL)
453 return 1;
454
455 PARSE_COMMA(1);
456
457 /* Parse the load address. */
458 rest = parse_u32(rest, &load_addr);
459 if (rest == NULL)
460 return 1;
461
462 PARSE_COMMA(1);
463
464 /* Parse the entry point. */
465 rest = parse_u32(rest, &entry_point);
466 if (rest == NULL)
467 return 1;
468
469 PARSE_COMMA(1);
470
471 /* Parse the end state. */
472 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
473 if (rest == NULL)
474 return 1;
475 if (strncmp(e_state, "Complete", strlen("Complete")))
476 return 1;
477
478 /* Parsing has finished - set the bootloader */
479 return set_mts_image(context, filename, load_addr, entry_point);
480}
481
482/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800483 * Parse the given string and find the array items in config file.
484 *
485 * @param context The main context pointer
486 * @param token The parse token value
487 * @param rest String to parse
488 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500489 */
490static int
491parse_array(build_image_context *context, parse_token token, char *rest)
492{
493 u_int32_t index;
494 u_int32_t value;
495
496 assert(context != NULL);
497 assert(rest != NULL);
498
499 /* Parse the index. */
500 rest = parse_u32(rest, &index);
501 if (rest == NULL)
502 return 1;
503
504 /* Parse the closing bracket. */
505 if (*rest != ']')
506 return 1;
507 rest++;
508
509 /* Parse the equals sign.*/
510 if (*rest != '=')
511 return 1;
512 rest++;
513
514 /* Parse the value based on the field table. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800515 switch (token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800516 case token_attribute:
517 rest = parse_u32(rest, &value);
518 break;
519 case token_dev_type:
Peer Chen6f2cbc72012-03-13 11:12:39 +0800520 rest = parse_enum(context,
521 rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800522 g_soc_config->devtype_table,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800523 &value);
Peer Chen7557d9b2011-02-24 09:29:23 -0800524 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500525
Peer Chen7557d9b2011-02-24 09:29:23 -0800526 default:
527 /* Unknown token */
528 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500529 }
530
531 if (rest == NULL)
532 return 1;
533
534 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800535 return set_array(context, index, token, value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500536}
537
538/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800539 * Call hw interface to set the value for array item in bct such as device
540 * type and bootloader attribute.
541 *
542 * @param context The main context pointer
543 * @param index The index for array
544 * @param token The parse token value
545 * @param value The value to set
546 * @return 0 and -ENODATA for success and failure
547 */
548
549static int
550set_array(build_image_context *context,
551 u_int32_t index,
552 parse_token token,
553 u_int32_t value)
554{
555 int err = 0;
556
557 assert(context != NULL);
558
559 switch (token) {
560 case token_attribute:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800561 err = g_soc_config->setbl_param(index,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800562 token_bl_attribute,
563 &value,
564 context->bct);
565 break;
566 case token_dev_type:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800567 err = g_soc_config->set_dev_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800568 index,
569 token_dev_type,
570 value);
571 break;
572 default:
573 break;
574 }
575 return err;
576}
577
578/*
579 * General handler for setting u_int32_t values in config files.
580 *
581 * @param context The main context pointer
582 * @param token The parse token value
583 * @param rest String to parse
584 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500585 */
586static int parse_value_u32(build_image_context *context,
587 parse_token token,
588 char *rest)
589{
590 u_int32_t value;
591
592 assert(context != NULL);
593 assert(rest != NULL);
594
595 rest = parse_u32(rest, &value);
596 if (rest == NULL)
597 return 1;
598
Penny Chiub81d2192014-04-11 17:50:39 +0800599 return context_set_value(context, token, &value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500600}
601
Peer Chen6f2cbc72012-03-13 11:12:39 +0800602/*
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800603 * General handler for setting chip uid in config files.
604 *
605 * @param context The main context pointer
606 * @param token The parse token value
607 * @param rest String to parse
608 * @return 0 and 1 for success and failure
609 */
610static int parse_value_chipuid(build_image_context *context,
611 parse_token token,
612 char *rest)
613{
614 u_int8_t value[16];
615
616 assert(context != NULL);
617 assert(rest != NULL);
618
619 rest = parse_chipuid(rest, value);
620 if (rest == NULL)
621 return 1;
622
623 return context_set_value(context, token, value);
624}
625
626/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800627 * Parse the given string and find the bct file name.
628 *
629 * @param context The main context pointer
630 * @param token The parse token value
631 * @param rest String to parse
632 * @return 0 and 1 for success and failure
633 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500634static int
635parse_bct_file(build_image_context *context, parse_token token, char *rest)
636{
637 char filename[MAX_BUFFER];
638
639 assert(context != NULL);
640 assert(rest != NULL);
641
642 /* Parse the file name. */
643 rest = parse_filename(rest, filename, MAX_BUFFER);
644 if (rest == NULL)
645 return 1;
646
647 /* Parsing has finished - set the bctfile */
648 context->bct_filename = filename;
649 /* Read the bct file to buffer */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800650 if (read_bct_file(context))
651 return 1;
652
Peer Chen6f2cbc72012-03-13 11:12:39 +0800653 update_context(context);
Peer Chen8d782ee2011-01-18 21:34:18 -0500654 return 0;
655}
656
657static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800658parse_end_state(char *str, char *uname, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500659{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800660 while (isalpha(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500661
Peer Chen6f2cbc72012-03-13 11:12:39 +0800662 *uname++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500663 if (--chars_remaining < 0)
664 return NULL;
665 }
666 *uname = '\0';
Peer Chen6f2cbc72012-03-13 11:12:39 +0800667 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500668}
669
Peer Chen6f2cbc72012-03-13 11:12:39 +0800670/*
671 * Parse the given string and find device parameter listed in device table
672 * and value for this device parameter. If match, call the corresponding
673 * function in the table to set device parameter.
674 *
675 * @param context The main context pointer
676 * @param token The parse token value
677 * @param rest String to parse
678 * @return 0 and 1 for success and failure
679 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800680static int
681parse_dev_param(build_image_context *context, parse_token token, char *rest)
682{
683 u_int32_t i;
684 u_int32_t value;
685 field_item *field;
686 u_int32_t index;
687 parse_subfield_item *device_item = NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800688
Peer Chen7557d9b2011-02-24 09:29:23 -0800689 assert(context != NULL);
690 assert(rest != NULL);
691
692 /* Parse the index. */
693 rest = parse_u32(rest, &index);
694 if (rest == NULL)
695 return 1;
696
697 /* Parse the closing bracket. */
698 if (*rest != ']')
699 return 1;
700 rest++;
701
702 /* Parse the following '.' */
703 if (*rest != '.')
704 return 1;
705 rest++;
706
707 /* Parse the device name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800708 for (i = 0; g_soc_config->device_type_table[i].prefix != NULL; i++) {
709 if (!strncmp(g_soc_config->device_type_table[i].prefix,
710 rest, strlen(g_soc_config->device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800711
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800712 device_item = &(g_soc_config->device_type_table[i]);
713 rest = rest + strlen(g_soc_config->device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800714
715 /* Parse the field name. */
716 rest = parse_field_name(rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800717 g_soc_config->device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800718 &field);
719 if (rest == NULL)
720 return 1;
721
722 /* Parse the equals sign.*/
723 if (*rest != '=')
724 return 1;
725 rest++;
726
727 /* Parse the value based on the field table. */
728 rest = parse_field_value(context, rest, field, &value);
729 if (rest == NULL)
730 return 1;
731 return device_item->process(context,
732 index, field->token, value);
733 }
734 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800735 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800736}
Peer Chen3a834ed2011-03-04 09:30:05 -0800737
Peer Chen6f2cbc72012-03-13 11:12:39 +0800738/*
739 * Parse the given string and find sdram parameter and value in config
740 * file. If match, call the corresponding function set the sdram parameter.
741 *
742 * @param context The main context pointer
743 * @param token The parse token value
744 * @param rest String to parse
745 * @return 0 and 1 for success and failure
746 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800747static int
748parse_sdram_param(build_image_context *context, parse_token token, char *rest)
749{
750 u_int32_t value;
751 field_item *field;
752 u_int32_t index;
753
754 assert(context != NULL);
755 assert(rest != NULL);
756
757 /* Parse the index. */
758 rest = parse_u32(rest, &index);
759 if (rest == NULL)
760 return 1;
761
762 /* Parse the closing bracket. */
763 if (*rest != ']')
764 return 1;
765 rest++;
766
767 /* Parse the following '.' */
768 if (*rest != '.')
769 return 1;
770 rest++;
771
772 /* Parse the field name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800773 rest = parse_field_name(rest, g_soc_config->sdram_field_table, &field);
774
Peer Chen3a834ed2011-03-04 09:30:05 -0800775 if (rest == NULL)
776 return 1;
777
778 /* Parse the equals sign.*/
779 if (*rest != '=')
780 return 1;
781 rest++;
782
783 /* Parse the value based on the field table. */
784 rest = parse_field_value(context, rest, field, &value);
785 if (rest == NULL)
786 return 1;
787
788 /* Store the result. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800789 return g_soc_config->set_sdram_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800790 index,
791 field->token,
792 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800793}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800794
795/*
796 * Compare the given string with item listed in table.
797 * Execute the proper process function if match.
798 *
799 * @param context The main context pointer
800 * @param str String to parse
801 * @param simple_parse Simple parse flag
802 * @return 0 and 1 for success and failure
803 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500804static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800805process_statement(build_image_context *context,
806 char *str,
807 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500808{
809 int i;
810 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800811 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500812
Peer Chen6f2cbc72012-03-13 11:12:39 +0800813 if (simple_parse == 0)
814 cfg_parse_item = s_top_level_items;
815 else
816 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500817
Peer Chen6f2cbc72012-03-13 11:12:39 +0800818 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
819 if (!strncmp(cfg_parse_item[i].prefix, str,
820 strlen(cfg_parse_item[i].prefix))) {
821 rest = str + strlen(cfg_parse_item[i].prefix);
822
823 return cfg_parse_item[i].process(context,
824 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500825 rest);
826 }
827 }
828
829 /* If this point was reached, there was a processing error. */
830 return 1;
831}
832
Peer Chen6f2cbc72012-03-13 11:12:39 +0800833/*
834 * The main function parse the config file.
835 *
836 * @param context The main context pointer
837 * @param simple_parse Simple parse flag
838 */
839void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500840{
841 char buffer[MAX_BUFFER];
842 int space = 0;
Stephen Warrenacbfad42013-01-17 14:41:28 -0700843 int current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800844 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500845 u_int8_t comment = 0;
846 u_int8_t string = 0;
847 u_int8_t equal_encounter = 0;
848
849 assert(context != NULL);
850 assert(context->config_file != NULL);
851
Peer Chen6f2cbc72012-03-13 11:12:39 +0800852 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500853 if (space >= (MAX_BUFFER-1)) {
854 /* if we exceeded the max buffer size, it is likely
855 due to a missing semi-colon at the end of a line */
856 printf("Config file parsing error!");
857 exit(1);
858 }
859
860 /* Handle failure to complete "//" comment token.
861 Insert the '/' into the busffer and proceed with
862 processing the current character. */
863 if (c_eol_comment_start && current != '/') {
864 c_eol_comment_start = 0;
865 buffer[space++] = '/';
866 }
867
868 switch (current) {
869 case '\"': /* " indicates start or end of a string */
870 if (!comment) {
871 string ^= 1;
872 buffer[space++] = current;
873 }
874 break;
875 case ';':
876 if (!string && !comment) {
877 buffer[space++] = '\0';
878
Peer Chen6f2cbc72012-03-13 11:12:39 +0800879 if (process_statement(context,
880 buffer,
881 simple_parse))
882 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500883 space = 0;
884 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800885 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500886 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500887 break;
888
889 case '/':
890 if (!string && !comment) {
891 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800892 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500893 comment = 1;
894 c_eol_comment_start = 0;
895 } else {
896 /* Potential start of eol comment. */
897 c_eol_comment_start = 1;
898 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800899 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500900 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500901 break;
902
903 /* ignore whitespace. uses fallthrough */
904 case '\n':
905 case '\r': /* carriage returns end comments */
906 string = 0;
907 comment = 0;
908 c_eol_comment_start = 0;
909 case ' ':
910 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800911 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500912 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500913 break;
914
915 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800916 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500917 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800918 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500919 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500920 break;
921
922 default:
923 if (!comment) {
924 buffer[space++] = current;
925 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800926 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500927 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800928 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500929 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500930 }
931 }
932 break;
933 }
934 }
935
936 return;
937
938 error:
939 printf("Error parsing: %s\n", buffer);
940 exit(1);
941}