blob: 7ccd594b24317f585381767565c74cd0cc167ffa [file] [log] [blame]
Stephen Warren4b0e5d02012-11-28 11:44:50 -07001/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
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
66parse_value_u32(build_image_context *context, parse_token token, char *rest);
67static int
Penny Chiu5f0b21a2014-04-11 17:50:42 +080068parse_value_chipuid(build_image_context *context,
69 parse_token token,
70 char *rest);
71static int
Peer Chen8d782ee2011-01-18 21:34:18 -050072parse_bct_file(build_image_context *context, parse_token token, char *rest);
Peer Chen8d782ee2011-01-18 21:34:18 -050073static char
Peer Chen6f2cbc72012-03-13 11:12:39 +080074*parse_end_state(char *str, char *uname, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080075static int
76parse_dev_param(build_image_context *context, parse_token token, char *rest);
Peer Chen3a834ed2011-03-04 09:30:05 -080077static int
78parse_sdram_param(build_image_context *context, parse_token token, char *rest);
Peer Chen7557d9b2011-02-24 09:29:23 -080079
Peer Chen6f2cbc72012-03-13 11:12:39 +080080static int process_statement(build_image_context *context,
81 char *str,
82 u_int8_t simple_parse);
Peer Chen8d782ee2011-01-18 21:34:18 -050083
Peer Chen6f2cbc72012-03-13 11:12:39 +080084static parse_item parse_simple_items[] =
Peer Chen7557d9b2011-02-24 09:29:23 -080085{
Peer Chen6f2cbc72012-03-13 11:12:39 +080086 { "Bctfile=", token_bct_file, parse_bct_file },
87 { "BootLoader=", token_bootloader, parse_bootloader },
88 { "Redundancy=", token_redundancy, parse_value_u32 },
89 { "Bctcopy=", token_bct_copy, parse_value_u32 },
90 { "Version=", token_version, parse_value_u32 },
Stephen Warrenf13abb02012-05-16 14:56:55 -060091 { "PreBctPadBlocks=", token_pre_bct_pad_blocks, parse_value_u32 },
Peer Chen6f2cbc72012-03-13 11:12:39 +080092 { NULL, 0, NULL } /* Must be last */
Peer Chen7557d9b2011-02-24 09:29:23 -080093};
94
Peer Chen6f2cbc72012-03-13 11:12:39 +080095static parse_item s_top_level_items[] = {
Peer Chen053d5782011-03-03 10:12:58 -080096 { "Bctfile=", token_bct_file, parse_bct_file },
97 { "Attribute=", token_attribute, parse_value_u32 },
98 { "Attribute[", token_attribute, parse_array },
99 { "PageSize=", token_page_size, parse_value_u32 },
100 { "BlockSize=", token_block_size, parse_value_u32 },
101 { "PartitionSize=", token_partition_size, parse_value_u32 },
102 { "DevType[", token_dev_type, parse_array },
103 { "DeviceParam[", token_dev_param, parse_dev_param },
Peer Chen3a834ed2011-03-04 09:30:05 -0800104 { "SDRAM[", token_sdram, parse_sdram_param },
Peer Chen053d5782011-03-03 10:12:58 -0800105 { "BootLoader=", token_bootloader, parse_bootloader },
106 { "Redundancy=", token_redundancy, parse_value_u32 },
Peer Chen56f40482011-07-27 02:59:41 -0400107 { "Bctcopy=", token_bct_copy, parse_value_u32 },
Peer Chen053d5782011-03-03 10:12:58 -0800108 { "Version=", token_version, parse_value_u32 },
Stephen Warrenfb4793a2012-05-16 14:38:17 -0600109 { "OdmData=", token_odm_data, parse_value_u32 },
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800110 { "ChipUid=", token_unique_chip_id, parse_value_chipuid },
111 { "JtagCtrl=", token_secure_jtag_control, parse_value_u32 },
Peer Chen8d782ee2011-01-18 21:34:18 -0500112 { NULL, 0, NULL } /* Must be last */
113};
114
115/* Macro to simplify parser code a bit. */
116#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
117
Peer Chen6f2cbc72012-03-13 11:12:39 +0800118/*
119 * Parse the given string and find the u32 dec/hex number.
120 *
121 * @param str String to parse
122 * @param val Returns value that was parsed
123 * @return the remainder of the string after the number was parsed
124 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500125static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800126parse_u32(char *str, u_int32_t *val)
Peer Chen8d782ee2011-01-18 21:34:18 -0500127{
128 u_int32_t value = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800129 u_int32_t digit;
Peer Chen8d782ee2011-01-18 21:34:18 -0500130
Peer Chen6f2cbc72012-03-13 11:12:39 +0800131 while (*str == '0')
132 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500133
Peer Chen6f2cbc72012-03-13 11:12:39 +0800134 if (tolower(*str) == 'x') {
135 str++;
136 while (isxdigit(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500137 value *= 16;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800138 digit = tolower(*str);
139 value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
140 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500141 }
142 } else {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800143 while (*str >= '0' && *str <= '9') {
144 value = value*10 + (*str - '0');
145 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500146 }
147 }
148 *val = value;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800149 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500150}
151
Peer Chen6f2cbc72012-03-13 11:12:39 +0800152/*
153 * Parse the given string and find the u8 dec/hex number.
154 *
155 * @param str String to parse
156 * @param val Returns value that was parsed
157 * @return the remainder of the string after the number was parsed
158 */
159static char *
160parse_u8(char *str, u_int32_t *val)
Peer Chen7557d9b2011-02-24 09:29:23 -0800161{
162 char *retval;
163
Peer Chen6f2cbc72012-03-13 11:12:39 +0800164 retval = parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800165
166 if (*val > 0xff) {
167 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
168 printf(" Parsed value = %d. Remaining text = %s\n",
169 *val, retval);
170 }
171
172 return retval;
173}
174
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800175/*
176 * Parse the given string and transfer to chip uid.
177 *
178 * @param str String to parse
179 * @param chipuid Returns chip uid that was parsed
180 * @return the remainder of the string after the number was parsed
181 */
182static char *
183parse_chipuid(char *str, u_int8_t *chipuid)
184{
185 int byte_index = 0;
186 int paddings = 0;
187 char byte_str[3];
188
189 if (*str++ != '0')
190 return NULL;
191
192 if (*str++ != 'x')
193 return NULL;
194
195 paddings = strlen(str) % 2;
196 byte_index = strlen(str) / 2 + paddings;
197
198 if (byte_index > 16)
199 return NULL;
200
201 memset(chipuid, 0, 16);
202
203 while (*str != '\0' && byte_index > 0) {
204 char *endptr;
205
206 strncpy(byte_str, str, 2 - paddings);
207 byte_str[2 - paddings] = '\0';
208 str += 2 - paddings;
209
210 chipuid[byte_index - 1] = strtoul(byte_str, &endptr, 16);
211 if (*endptr)
212 return NULL;
213
214 byte_index--;
215 paddings = 0;
216 }
217
218 return str;
219}
Peer Chen7557d9b2011-02-24 09:29:23 -0800220
Peer Chen6f2cbc72012-03-13 11:12:39 +0800221/*
222 * Parse the given string and find the file name then
223 * return the rest of the string.
224 *
225 * @param str String to parse
226 * @param name Returns the filename that was parsed
227 * @param chars_remaining The maximum length of filename
228 * @return the remainder of the string after the name was parsed
229 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500230static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800231parse_filename(char *str, char *name, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500232{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800233 /*
234 * Check if the filename buffer is out of space, preserving one
235 * character to null terminate the string.
236 */
237 while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
238
Peer Chen8d782ee2011-01-18 21:34:18 -0500239 chars_remaining--;
240
241 if (chars_remaining < 1)
242 return NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800243 *name++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500244 }
245
246 /* Null terminate the filename. */
247 *name = '\0';
248
Peer Chen6f2cbc72012-03-13 11:12:39 +0800249 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500250}
251
Peer Chen6f2cbc72012-03-13 11:12:39 +0800252/*
253 * Parse the given string and find the match field name listed
254 * in field table.
255 *
256 * @param rest String to parse
257 * @param field_table The field table to parse
258 * @param field Returns the field item that was parsed
259 * @return NULL or the remainder of the string after the field item was parsed
260 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800261static char
262*parse_field_name(char *rest, field_item *field_table, field_item **field)
263{
264 u_int32_t i;
265 u_int32_t field_name_len = 0;
266
267 assert(field_table != NULL);
268 assert(rest != NULL);
269 assert(field != NULL);
270
Peer Chen6f2cbc72012-03-13 11:12:39 +0800271 while (rest[field_name_len] != '=')
Peer Chen7557d9b2011-02-24 09:29:23 -0800272 field_name_len++;
273
274 /* Parse the field name. */
275 for (i = 0; field_table[i].name != NULL; i++) {
276 if ((strlen(field_table[i].name) == field_name_len) &&
277 !strncmp(field_table[i].name,
278 rest,
279 field_name_len)) {
280
281 *field = &(field_table[i]);
282 rest = rest + field_name_len;
283 return rest;
284 }
285 }
286
287 /* Field wasn't found or a parse error occurred. */
288 return NULL;
289}
290
Peer Chen6f2cbc72012-03-13 11:12:39 +0800291/*
292 * Parse the value based on the field table
293 *
294 * @param context The main context pointer
295 * @param rest String to parse
296 * @param field Field item to parse
297 * @param value Returns the value that was parsed
298 * @return the remainder of the string after the value was parsed
299 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800300static char
Peer Chen6f2cbc72012-03-13 11:12:39 +0800301*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -0800302 char *rest,
303 field_item *field,
304 u_int32_t *value)
305{
306 assert(rest != NULL);
307 assert(field != NULL);
308 assert((field->type != field_type_enum)
309 || (field->enum_table != NULL));
310
311 switch (field->type) {
312 case field_type_enum:
313 rest = parse_enum(context, rest, field->enum_table, value);
314 break;
315
316 case field_type_u32:
317 rest = parse_u32(rest, value);
318 break;
319
320 case field_type_u8:
321 rest = parse_u8(rest, value);
322 break;
323
324 default:
325 printf("Unexpected field type %d at line %d\n",
326 field->type, __LINE__);
327 rest = NULL;
328 break;
329 }
330
331 return rest;
332}
333
Peer Chen6f2cbc72012-03-13 11:12:39 +0800334/*
335 * Parse the given string and find the match enum item listed
336 * in table.
337 *
338 * @param context The main context pointer
339 * @param str String to parse
340 * @param table Enum item table to parse
341 * @param value Returns the value that was parsed
342 * @return the remainder of the string after the item was parsed
343 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800344static char *
345parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800346 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800347 enum_item *table,
348 u_int32_t *val)
349{
350 int i;
351 char *rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800352
353 for (i = 0; table[i].name != NULL; i++) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800354 if (!strncmp(table[i].name, str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800355 strlen(table[i].name))) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800356 *val = table[i].value;
357 rest = str + strlen(table[i].name);
358 return rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800359 }
360 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800361 return parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800362
363}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800364
Peer Chen8d782ee2011-01-18 21:34:18 -0500365/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800366 * Parse the given string and find the bootloader file name, load address and
367 * entry point information then call set_bootloader function.
368 *
369 * @param context The main context pointer
370 * @param token The parse token value
371 * @param rest String to parse
372 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500373 */
374static int parse_bootloader(build_image_context *context,
375 parse_token token,
376 char *rest)
377{
378 char filename[MAX_BUFFER];
379 char e_state[MAX_STR_LEN];
380 u_int32_t load_addr;
381 u_int32_t entry_point;
382
383 assert(context != NULL);
384 assert(rest != NULL);
385
Peer Chen7557d9b2011-02-24 09:29:23 -0800386 if (context->generate_bct != 0)
387 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500388 /* Parse the file name. */
389 rest = parse_filename(rest, filename, MAX_BUFFER);
390 if (rest == NULL)
391 return 1;
392
393 PARSE_COMMA(1);
394
395 /* Parse the load address. */
396 rest = parse_u32(rest, &load_addr);
397 if (rest == NULL)
398 return 1;
399
400 PARSE_COMMA(1);
401
402 /* Parse the entry point. */
403 rest = parse_u32(rest, &entry_point);
404 if (rest == NULL)
405 return 1;
406
407 PARSE_COMMA(1);
408
409 /* Parse the end state. */
410 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
411 if (rest == NULL)
412 return 1;
413 if (strncmp(e_state, "Complete", strlen("Complete")))
414 return 1;
415
416 /* Parsing has finished - set the bootloader */
417 return set_bootloader(context, filename, load_addr, entry_point);
418}
419
420/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800421 * Parse the given string and find the array items in config file.
422 *
423 * @param context The main context pointer
424 * @param token The parse token value
425 * @param rest String to parse
426 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500427 */
428static int
429parse_array(build_image_context *context, parse_token token, char *rest)
430{
431 u_int32_t index;
432 u_int32_t value;
433
434 assert(context != NULL);
435 assert(rest != NULL);
436
437 /* Parse the index. */
438 rest = parse_u32(rest, &index);
439 if (rest == NULL)
440 return 1;
441
442 /* Parse the closing bracket. */
443 if (*rest != ']')
444 return 1;
445 rest++;
446
447 /* Parse the equals sign.*/
448 if (*rest != '=')
449 return 1;
450 rest++;
451
452 /* Parse the value based on the field table. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800453 switch (token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800454 case token_attribute:
455 rest = parse_u32(rest, &value);
456 break;
457 case token_dev_type:
Peer Chen6f2cbc72012-03-13 11:12:39 +0800458 rest = parse_enum(context,
459 rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800460 g_soc_config->devtype_table,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800461 &value);
Peer Chen7557d9b2011-02-24 09:29:23 -0800462 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500463
Peer Chen7557d9b2011-02-24 09:29:23 -0800464 default:
465 /* Unknown token */
466 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500467 }
468
469 if (rest == NULL)
470 return 1;
471
472 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800473 return set_array(context, index, token, value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500474}
475
476/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800477 * Call hw interface to set the value for array item in bct such as device
478 * type and bootloader attribute.
479 *
480 * @param context The main context pointer
481 * @param index The index for array
482 * @param token The parse token value
483 * @param value The value to set
484 * @return 0 and -ENODATA for success and failure
485 */
486
487static int
488set_array(build_image_context *context,
489 u_int32_t index,
490 parse_token token,
491 u_int32_t value)
492{
493 int err = 0;
494
495 assert(context != NULL);
496
497 switch (token) {
498 case token_attribute:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800499 err = g_soc_config->setbl_param(index,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800500 token_bl_attribute,
501 &value,
502 context->bct);
503 break;
504 case token_dev_type:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800505 err = g_soc_config->set_dev_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800506 index,
507 token_dev_type,
508 value);
509 break;
510 default:
511 break;
512 }
513 return err;
514}
515
516/*
517 * General handler for setting u_int32_t values in config files.
518 *
519 * @param context The main context pointer
520 * @param token The parse token value
521 * @param rest String to parse
522 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500523 */
524static int parse_value_u32(build_image_context *context,
525 parse_token token,
526 char *rest)
527{
528 u_int32_t value;
529
530 assert(context != NULL);
531 assert(rest != NULL);
532
533 rest = parse_u32(rest, &value);
534 if (rest == NULL)
535 return 1;
536
Penny Chiub81d2192014-04-11 17:50:39 +0800537 return context_set_value(context, token, &value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500538}
539
Peer Chen6f2cbc72012-03-13 11:12:39 +0800540/*
Penny Chiu5f0b21a2014-04-11 17:50:42 +0800541 * General handler for setting chip uid in config files.
542 *
543 * @param context The main context pointer
544 * @param token The parse token value
545 * @param rest String to parse
546 * @return 0 and 1 for success and failure
547 */
548static int parse_value_chipuid(build_image_context *context,
549 parse_token token,
550 char *rest)
551{
552 u_int8_t value[16];
553
554 assert(context != NULL);
555 assert(rest != NULL);
556
557 rest = parse_chipuid(rest, value);
558 if (rest == NULL)
559 return 1;
560
561 return context_set_value(context, token, value);
562}
563
564/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800565 * Parse the given string and find the bct file name.
566 *
567 * @param context The main context pointer
568 * @param token The parse token value
569 * @param rest String to parse
570 * @return 0 and 1 for success and failure
571 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500572static int
573parse_bct_file(build_image_context *context, parse_token token, char *rest)
574{
575 char filename[MAX_BUFFER];
576
577 assert(context != NULL);
578 assert(rest != NULL);
579
580 /* Parse the file name. */
581 rest = parse_filename(rest, filename, MAX_BUFFER);
582 if (rest == NULL)
583 return 1;
584
585 /* Parsing has finished - set the bctfile */
586 context->bct_filename = filename;
587 /* Read the bct file to buffer */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800588 if (read_bct_file(context))
589 return 1;
590
Peer Chen6f2cbc72012-03-13 11:12:39 +0800591 update_context(context);
Peer Chen8d782ee2011-01-18 21:34:18 -0500592 return 0;
593}
594
595static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800596parse_end_state(char *str, char *uname, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500597{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800598 while (isalpha(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500599
Peer Chen6f2cbc72012-03-13 11:12:39 +0800600 *uname++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500601 if (--chars_remaining < 0)
602 return NULL;
603 }
604 *uname = '\0';
Peer Chen6f2cbc72012-03-13 11:12:39 +0800605 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500606}
607
Peer Chen6f2cbc72012-03-13 11:12:39 +0800608/*
609 * Parse the given string and find device parameter listed in device table
610 * and value for this device parameter. If match, call the corresponding
611 * function in the table to set device parameter.
612 *
613 * @param context The main context pointer
614 * @param token The parse token value
615 * @param rest String to parse
616 * @return 0 and 1 for success and failure
617 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800618static int
619parse_dev_param(build_image_context *context, parse_token token, char *rest)
620{
621 u_int32_t i;
622 u_int32_t value;
623 field_item *field;
624 u_int32_t index;
625 parse_subfield_item *device_item = NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800626
Peer Chen7557d9b2011-02-24 09:29:23 -0800627 assert(context != NULL);
628 assert(rest != NULL);
629
630 /* Parse the index. */
631 rest = parse_u32(rest, &index);
632 if (rest == NULL)
633 return 1;
634
635 /* Parse the closing bracket. */
636 if (*rest != ']')
637 return 1;
638 rest++;
639
640 /* Parse the following '.' */
641 if (*rest != '.')
642 return 1;
643 rest++;
644
645 /* Parse the device name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800646 for (i = 0; g_soc_config->device_type_table[i].prefix != NULL; i++) {
647 if (!strncmp(g_soc_config->device_type_table[i].prefix,
648 rest, strlen(g_soc_config->device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800649
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800650 device_item = &(g_soc_config->device_type_table[i]);
651 rest = rest + strlen(g_soc_config->device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800652
653 /* Parse the field name. */
654 rest = parse_field_name(rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800655 g_soc_config->device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800656 &field);
657 if (rest == NULL)
658 return 1;
659
660 /* Parse the equals sign.*/
661 if (*rest != '=')
662 return 1;
663 rest++;
664
665 /* Parse the value based on the field table. */
666 rest = parse_field_value(context, rest, field, &value);
667 if (rest == NULL)
668 return 1;
669 return device_item->process(context,
670 index, field->token, value);
671 }
672 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800673 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800674}
Peer Chen3a834ed2011-03-04 09:30:05 -0800675
Peer Chen6f2cbc72012-03-13 11:12:39 +0800676/*
677 * Parse the given string and find sdram parameter and value in config
678 * file. If match, call the corresponding function set the sdram parameter.
679 *
680 * @param context The main context pointer
681 * @param token The parse token value
682 * @param rest String to parse
683 * @return 0 and 1 for success and failure
684 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800685static int
686parse_sdram_param(build_image_context *context, parse_token token, char *rest)
687{
688 u_int32_t value;
689 field_item *field;
690 u_int32_t index;
691
692 assert(context != NULL);
693 assert(rest != NULL);
694
695 /* Parse the index. */
696 rest = parse_u32(rest, &index);
697 if (rest == NULL)
698 return 1;
699
700 /* Parse the closing bracket. */
701 if (*rest != ']')
702 return 1;
703 rest++;
704
705 /* Parse the following '.' */
706 if (*rest != '.')
707 return 1;
708 rest++;
709
710 /* Parse the field name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800711 rest = parse_field_name(rest, g_soc_config->sdram_field_table, &field);
712
Peer Chen3a834ed2011-03-04 09:30:05 -0800713 if (rest == NULL)
714 return 1;
715
716 /* Parse the equals sign.*/
717 if (*rest != '=')
718 return 1;
719 rest++;
720
721 /* Parse the value based on the field table. */
722 rest = parse_field_value(context, rest, field, &value);
723 if (rest == NULL)
724 return 1;
725
726 /* Store the result. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800727 return g_soc_config->set_sdram_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800728 index,
729 field->token,
730 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800731}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800732
733/*
734 * Compare the given string with item listed in table.
735 * Execute the proper process function if match.
736 *
737 * @param context The main context pointer
738 * @param str String to parse
739 * @param simple_parse Simple parse flag
740 * @return 0 and 1 for success and failure
741 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500742static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800743process_statement(build_image_context *context,
744 char *str,
745 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500746{
747 int i;
748 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800749 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500750
Peer Chen6f2cbc72012-03-13 11:12:39 +0800751 if (simple_parse == 0)
752 cfg_parse_item = s_top_level_items;
753 else
754 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500755
Peer Chen6f2cbc72012-03-13 11:12:39 +0800756 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
757 if (!strncmp(cfg_parse_item[i].prefix, str,
758 strlen(cfg_parse_item[i].prefix))) {
759 rest = str + strlen(cfg_parse_item[i].prefix);
760
761 return cfg_parse_item[i].process(context,
762 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500763 rest);
764 }
765 }
766
767 /* If this point was reached, there was a processing error. */
768 return 1;
769}
770
Peer Chen6f2cbc72012-03-13 11:12:39 +0800771/*
772 * The main function parse the config file.
773 *
774 * @param context The main context pointer
775 * @param simple_parse Simple parse flag
776 */
777void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500778{
779 char buffer[MAX_BUFFER];
780 int space = 0;
Stephen Warrenacbfad42013-01-17 14:41:28 -0700781 int current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800782 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500783 u_int8_t comment = 0;
784 u_int8_t string = 0;
785 u_int8_t equal_encounter = 0;
786
787 assert(context != NULL);
788 assert(context->config_file != NULL);
789
Peer Chen6f2cbc72012-03-13 11:12:39 +0800790 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500791 if (space >= (MAX_BUFFER-1)) {
792 /* if we exceeded the max buffer size, it is likely
793 due to a missing semi-colon at the end of a line */
794 printf("Config file parsing error!");
795 exit(1);
796 }
797
798 /* Handle failure to complete "//" comment token.
799 Insert the '/' into the busffer and proceed with
800 processing the current character. */
801 if (c_eol_comment_start && current != '/') {
802 c_eol_comment_start = 0;
803 buffer[space++] = '/';
804 }
805
806 switch (current) {
807 case '\"': /* " indicates start or end of a string */
808 if (!comment) {
809 string ^= 1;
810 buffer[space++] = current;
811 }
812 break;
813 case ';':
814 if (!string && !comment) {
815 buffer[space++] = '\0';
816
Peer Chen6f2cbc72012-03-13 11:12:39 +0800817 if (process_statement(context,
818 buffer,
819 simple_parse))
820 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500821 space = 0;
822 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800823 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500824 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500825 break;
826
827 case '/':
828 if (!string && !comment) {
829 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800830 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500831 comment = 1;
832 c_eol_comment_start = 0;
833 } else {
834 /* Potential start of eol comment. */
835 c_eol_comment_start = 1;
836 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800837 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500838 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500839 break;
840
841 /* ignore whitespace. uses fallthrough */
842 case '\n':
843 case '\r': /* carriage returns end comments */
844 string = 0;
845 comment = 0;
846 c_eol_comment_start = 0;
847 case ' ':
848 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800849 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500850 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500851 break;
852
853 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800854 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500855 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800856 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500857 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500858 break;
859
860 default:
861 if (!comment) {
862 buffer[space++] = current;
863 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800864 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500865 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800866 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500867 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500868 }
869 }
870 break;
871 }
872 }
873
874 return;
875
876 error:
877 printf("Error parsing: %s\n", buffer);
878 exit(1);
879}