blob: 464ee8ff40e4c0bc835f75010cfe990d6ef7a2b1 [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);
48static char *parse_filename(char *str, char *name, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080049static char *parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +080050 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -080051 enum_item *table,
52 u_int32_t *val);
53static char
54*parse_field_name(char *rest, field_item *field_table, field_item **field);
55static char
Anton Staafe517a4f2011-03-14 12:28:06 -070056*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -080057 char *rest,
58 field_item *field,
59 u_int32_t *value);
Peer Chen8d782ee2011-01-18 21:34:18 -050060static int
61parse_array(build_image_context *context, parse_token token, char *rest);
62static int
63parse_bootloader(build_image_context *context, parse_token token, char *rest);
64static int
65parse_value_u32(build_image_context *context, parse_token token, char *rest);
66static int
67parse_bct_file(build_image_context *context, parse_token token, char *rest);
Peer Chen8d782ee2011-01-18 21:34:18 -050068static char
Peer Chen6f2cbc72012-03-13 11:12:39 +080069*parse_end_state(char *str, char *uname, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080070static int
71parse_dev_param(build_image_context *context, parse_token token, char *rest);
Peer Chen3a834ed2011-03-04 09:30:05 -080072static int
73parse_sdram_param(build_image_context *context, parse_token token, char *rest);
Peer Chen7557d9b2011-02-24 09:29:23 -080074
Peer Chen6f2cbc72012-03-13 11:12:39 +080075static int process_statement(build_image_context *context,
76 char *str,
77 u_int8_t simple_parse);
Peer Chen8d782ee2011-01-18 21:34:18 -050078
Peer Chen6f2cbc72012-03-13 11:12:39 +080079static parse_item parse_simple_items[] =
Peer Chen7557d9b2011-02-24 09:29:23 -080080{
Peer Chen6f2cbc72012-03-13 11:12:39 +080081 { "Bctfile=", token_bct_file, parse_bct_file },
82 { "BootLoader=", token_bootloader, parse_bootloader },
83 { "Redundancy=", token_redundancy, parse_value_u32 },
84 { "Bctcopy=", token_bct_copy, parse_value_u32 },
85 { "Version=", token_version, parse_value_u32 },
Stephen Warrenf13abb02012-05-16 14:56:55 -060086 { "PreBctPadBlocks=", token_pre_bct_pad_blocks, parse_value_u32 },
Peer Chen6f2cbc72012-03-13 11:12:39 +080087 { NULL, 0, NULL } /* Must be last */
Peer Chen7557d9b2011-02-24 09:29:23 -080088};
89
Peer Chen6f2cbc72012-03-13 11:12:39 +080090static parse_item s_top_level_items[] = {
Peer Chen053d5782011-03-03 10:12:58 -080091 { "Bctfile=", token_bct_file, parse_bct_file },
92 { "Attribute=", token_attribute, parse_value_u32 },
93 { "Attribute[", token_attribute, parse_array },
94 { "PageSize=", token_page_size, parse_value_u32 },
95 { "BlockSize=", token_block_size, parse_value_u32 },
96 { "PartitionSize=", token_partition_size, parse_value_u32 },
97 { "DevType[", token_dev_type, parse_array },
98 { "DeviceParam[", token_dev_param, parse_dev_param },
Peer Chen3a834ed2011-03-04 09:30:05 -080099 { "SDRAM[", token_sdram, parse_sdram_param },
Peer Chen053d5782011-03-03 10:12:58 -0800100 { "BootLoader=", token_bootloader, parse_bootloader },
101 { "Redundancy=", token_redundancy, parse_value_u32 },
Peer Chen56f40482011-07-27 02:59:41 -0400102 { "Bctcopy=", token_bct_copy, parse_value_u32 },
Peer Chen053d5782011-03-03 10:12:58 -0800103 { "Version=", token_version, parse_value_u32 },
Stephen Warrenfb4793a2012-05-16 14:38:17 -0600104 { "OdmData=", token_odm_data, parse_value_u32 },
Peer Chen8d782ee2011-01-18 21:34:18 -0500105 { NULL, 0, NULL } /* Must be last */
106};
107
108/* Macro to simplify parser code a bit. */
109#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
110
Peer Chen6f2cbc72012-03-13 11:12:39 +0800111/*
112 * Parse the given string and find the u32 dec/hex number.
113 *
114 * @param str String to parse
115 * @param val Returns value that was parsed
116 * @return the remainder of the string after the number was parsed
117 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500118static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800119parse_u32(char *str, u_int32_t *val)
Peer Chen8d782ee2011-01-18 21:34:18 -0500120{
121 u_int32_t value = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800122 u_int32_t digit;
Peer Chen8d782ee2011-01-18 21:34:18 -0500123
Peer Chen6f2cbc72012-03-13 11:12:39 +0800124 while (*str == '0')
125 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500126
Peer Chen6f2cbc72012-03-13 11:12:39 +0800127 if (tolower(*str) == 'x') {
128 str++;
129 while (isxdigit(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500130 value *= 16;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800131 digit = tolower(*str);
132 value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
133 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500134 }
135 } else {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800136 while (*str >= '0' && *str <= '9') {
137 value = value*10 + (*str - '0');
138 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500139 }
140 }
141 *val = value;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800142 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500143}
144
Peer Chen6f2cbc72012-03-13 11:12:39 +0800145/*
146 * Parse the given string and find the u8 dec/hex number.
147 *
148 * @param str String to parse
149 * @param val Returns value that was parsed
150 * @return the remainder of the string after the number was parsed
151 */
152static char *
153parse_u8(char *str, u_int32_t *val)
Peer Chen7557d9b2011-02-24 09:29:23 -0800154{
155 char *retval;
156
Peer Chen6f2cbc72012-03-13 11:12:39 +0800157 retval = parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800158
159 if (*val > 0xff) {
160 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
161 printf(" Parsed value = %d. Remaining text = %s\n",
162 *val, retval);
163 }
164
165 return retval;
166}
167
168
Peer Chen6f2cbc72012-03-13 11:12:39 +0800169/*
170 * Parse the given string and find the file name then
171 * return the rest of the string.
172 *
173 * @param str String to parse
174 * @param name Returns the filename that was parsed
175 * @param chars_remaining The maximum length of filename
176 * @return the remainder of the string after the name was parsed
177 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500178static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800179parse_filename(char *str, char *name, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500180{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800181 /*
182 * Check if the filename buffer is out of space, preserving one
183 * character to null terminate the string.
184 */
185 while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
186
Peer Chen8d782ee2011-01-18 21:34:18 -0500187 chars_remaining--;
188
189 if (chars_remaining < 1)
190 return NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800191 *name++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500192 }
193
194 /* Null terminate the filename. */
195 *name = '\0';
196
Peer Chen6f2cbc72012-03-13 11:12:39 +0800197 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500198}
199
Peer Chen6f2cbc72012-03-13 11:12:39 +0800200/*
201 * Parse the given string and find the match field name listed
202 * in field table.
203 *
204 * @param rest String to parse
205 * @param field_table The field table to parse
206 * @param field Returns the field item that was parsed
207 * @return NULL or the remainder of the string after the field item was parsed
208 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800209static char
210*parse_field_name(char *rest, field_item *field_table, field_item **field)
211{
212 u_int32_t i;
213 u_int32_t field_name_len = 0;
214
215 assert(field_table != NULL);
216 assert(rest != NULL);
217 assert(field != NULL);
218
Peer Chen6f2cbc72012-03-13 11:12:39 +0800219 while (rest[field_name_len] != '=')
Peer Chen7557d9b2011-02-24 09:29:23 -0800220 field_name_len++;
221
222 /* Parse the field name. */
223 for (i = 0; field_table[i].name != NULL; i++) {
224 if ((strlen(field_table[i].name) == field_name_len) &&
225 !strncmp(field_table[i].name,
226 rest,
227 field_name_len)) {
228
229 *field = &(field_table[i]);
230 rest = rest + field_name_len;
231 return rest;
232 }
233 }
234
235 /* Field wasn't found or a parse error occurred. */
236 return NULL;
237}
238
Peer Chen6f2cbc72012-03-13 11:12:39 +0800239/*
240 * Parse the value based on the field table
241 *
242 * @param context The main context pointer
243 * @param rest String to parse
244 * @param field Field item to parse
245 * @param value Returns the value that was parsed
246 * @return the remainder of the string after the value was parsed
247 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800248static char
Peer Chen6f2cbc72012-03-13 11:12:39 +0800249*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -0800250 char *rest,
251 field_item *field,
252 u_int32_t *value)
253{
254 assert(rest != NULL);
255 assert(field != NULL);
256 assert((field->type != field_type_enum)
257 || (field->enum_table != NULL));
258
259 switch (field->type) {
260 case field_type_enum:
261 rest = parse_enum(context, rest, field->enum_table, value);
262 break;
263
264 case field_type_u32:
265 rest = parse_u32(rest, value);
266 break;
267
268 case field_type_u8:
269 rest = parse_u8(rest, value);
270 break;
271
272 default:
273 printf("Unexpected field type %d at line %d\n",
274 field->type, __LINE__);
275 rest = NULL;
276 break;
277 }
278
279 return rest;
280}
281
Peer Chen6f2cbc72012-03-13 11:12:39 +0800282/*
283 * Parse the given string and find the match enum item listed
284 * in table.
285 *
286 * @param context The main context pointer
287 * @param str String to parse
288 * @param table Enum item table to parse
289 * @param value Returns the value that was parsed
290 * @return the remainder of the string after the item was parsed
291 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800292static char *
293parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800294 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800295 enum_item *table,
296 u_int32_t *val)
297{
298 int i;
299 char *rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800300
301 for (i = 0; table[i].name != NULL; i++) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800302 if (!strncmp(table[i].name, str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800303 strlen(table[i].name))) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800304 *val = table[i].value;
305 rest = str + strlen(table[i].name);
306 return rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800307 }
308 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800309 return parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800310
311}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800312
Peer Chen8d782ee2011-01-18 21:34:18 -0500313/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800314 * Parse the given string and find the bootloader file name, load address and
315 * entry point information then call set_bootloader function.
316 *
317 * @param context The main context pointer
318 * @param token The parse token value
319 * @param rest String to parse
320 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500321 */
322static int parse_bootloader(build_image_context *context,
323 parse_token token,
324 char *rest)
325{
326 char filename[MAX_BUFFER];
327 char e_state[MAX_STR_LEN];
328 u_int32_t load_addr;
329 u_int32_t entry_point;
330
331 assert(context != NULL);
332 assert(rest != NULL);
333
Peer Chen7557d9b2011-02-24 09:29:23 -0800334 if (context->generate_bct != 0)
335 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500336 /* Parse the file name. */
337 rest = parse_filename(rest, filename, MAX_BUFFER);
338 if (rest == NULL)
339 return 1;
340
341 PARSE_COMMA(1);
342
343 /* Parse the load address. */
344 rest = parse_u32(rest, &load_addr);
345 if (rest == NULL)
346 return 1;
347
348 PARSE_COMMA(1);
349
350 /* Parse the entry point. */
351 rest = parse_u32(rest, &entry_point);
352 if (rest == NULL)
353 return 1;
354
355 PARSE_COMMA(1);
356
357 /* Parse the end state. */
358 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
359 if (rest == NULL)
360 return 1;
361 if (strncmp(e_state, "Complete", strlen("Complete")))
362 return 1;
363
364 /* Parsing has finished - set the bootloader */
365 return set_bootloader(context, filename, load_addr, entry_point);
366}
367
368/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800369 * Parse the given string and find the array items in config file.
370 *
371 * @param context The main context pointer
372 * @param token The parse token value
373 * @param rest String to parse
374 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500375 */
376static int
377parse_array(build_image_context *context, parse_token token, char *rest)
378{
379 u_int32_t index;
380 u_int32_t value;
381
382 assert(context != NULL);
383 assert(rest != NULL);
384
385 /* Parse the index. */
386 rest = parse_u32(rest, &index);
387 if (rest == NULL)
388 return 1;
389
390 /* Parse the closing bracket. */
391 if (*rest != ']')
392 return 1;
393 rest++;
394
395 /* Parse the equals sign.*/
396 if (*rest != '=')
397 return 1;
398 rest++;
399
400 /* Parse the value based on the field table. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800401 switch (token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800402 case token_attribute:
403 rest = parse_u32(rest, &value);
404 break;
405 case token_dev_type:
Peer Chen6f2cbc72012-03-13 11:12:39 +0800406 rest = parse_enum(context,
407 rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800408 g_soc_config->devtype_table,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800409 &value);
Peer Chen7557d9b2011-02-24 09:29:23 -0800410 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500411
Peer Chen7557d9b2011-02-24 09:29:23 -0800412 default:
413 /* Unknown token */
414 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500415 }
416
417 if (rest == NULL)
418 return 1;
419
420 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800421 return set_array(context, index, token, value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500422}
423
424/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800425 * Call hw interface to set the value for array item in bct such as device
426 * type and bootloader attribute.
427 *
428 * @param context The main context pointer
429 * @param index The index for array
430 * @param token The parse token value
431 * @param value The value to set
432 * @return 0 and -ENODATA for success and failure
433 */
434
435static int
436set_array(build_image_context *context,
437 u_int32_t index,
438 parse_token token,
439 u_int32_t value)
440{
441 int err = 0;
442
443 assert(context != NULL);
444
445 switch (token) {
446 case token_attribute:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800447 err = g_soc_config->setbl_param(index,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800448 token_bl_attribute,
449 &value,
450 context->bct);
451 break;
452 case token_dev_type:
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800453 err = g_soc_config->set_dev_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800454 index,
455 token_dev_type,
456 value);
457 break;
458 default:
459 break;
460 }
461 return err;
462}
463
464/*
465 * General handler for setting u_int32_t values in config files.
466 *
467 * @param context The main context pointer
468 * @param token The parse token value
469 * @param rest String to parse
470 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500471 */
472static int parse_value_u32(build_image_context *context,
473 parse_token token,
474 char *rest)
475{
476 u_int32_t value;
477
478 assert(context != NULL);
479 assert(rest != NULL);
480
481 rest = parse_u32(rest, &value);
482 if (rest == NULL)
483 return 1;
484
485 return context_set_value(context, token, value);
486}
487
Peer Chen6f2cbc72012-03-13 11:12:39 +0800488/*
489 * Parse the given string and find the bct file name.
490 *
491 * @param context The main context pointer
492 * @param token The parse token value
493 * @param rest String to parse
494 * @return 0 and 1 for success and failure
495 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500496static int
497parse_bct_file(build_image_context *context, parse_token token, char *rest)
498{
499 char filename[MAX_BUFFER];
500
501 assert(context != NULL);
502 assert(rest != NULL);
503
504 /* Parse the file name. */
505 rest = parse_filename(rest, filename, MAX_BUFFER);
506 if (rest == NULL)
507 return 1;
508
509 /* Parsing has finished - set the bctfile */
510 context->bct_filename = filename;
511 /* Read the bct file to buffer */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800512 if (read_bct_file(context))
513 return 1;
514
Peer Chen6f2cbc72012-03-13 11:12:39 +0800515 update_context(context);
Peer Chen8d782ee2011-01-18 21:34:18 -0500516 return 0;
517}
518
519static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800520parse_end_state(char *str, char *uname, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500521{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800522 while (isalpha(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500523
Peer Chen6f2cbc72012-03-13 11:12:39 +0800524 *uname++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500525 if (--chars_remaining < 0)
526 return NULL;
527 }
528 *uname = '\0';
Peer Chen6f2cbc72012-03-13 11:12:39 +0800529 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500530}
531
Peer Chen6f2cbc72012-03-13 11:12:39 +0800532/*
533 * Parse the given string and find device parameter listed in device table
534 * and value for this device parameter. If match, call the corresponding
535 * function in the table to set device parameter.
536 *
537 * @param context The main context pointer
538 * @param token The parse token value
539 * @param rest String to parse
540 * @return 0 and 1 for success and failure
541 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800542static int
543parse_dev_param(build_image_context *context, parse_token token, char *rest)
544{
545 u_int32_t i;
546 u_int32_t value;
547 field_item *field;
548 u_int32_t index;
549 parse_subfield_item *device_item = NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800550
Peer Chen7557d9b2011-02-24 09:29:23 -0800551 assert(context != NULL);
552 assert(rest != NULL);
553
554 /* Parse the index. */
555 rest = parse_u32(rest, &index);
556 if (rest == NULL)
557 return 1;
558
559 /* Parse the closing bracket. */
560 if (*rest != ']')
561 return 1;
562 rest++;
563
564 /* Parse the following '.' */
565 if (*rest != '.')
566 return 1;
567 rest++;
568
569 /* Parse the device name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800570 for (i = 0; g_soc_config->device_type_table[i].prefix != NULL; i++) {
571 if (!strncmp(g_soc_config->device_type_table[i].prefix,
572 rest, strlen(g_soc_config->device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800573
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800574 device_item = &(g_soc_config->device_type_table[i]);
575 rest = rest + strlen(g_soc_config->device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800576
577 /* Parse the field name. */
578 rest = parse_field_name(rest,
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800579 g_soc_config->device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800580 &field);
581 if (rest == NULL)
582 return 1;
583
584 /* Parse the equals sign.*/
585 if (*rest != '=')
586 return 1;
587 rest++;
588
589 /* Parse the value based on the field table. */
590 rest = parse_field_value(context, rest, field, &value);
591 if (rest == NULL)
592 return 1;
593 return device_item->process(context,
594 index, field->token, value);
595 }
596 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800597 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800598}
Peer Chen3a834ed2011-03-04 09:30:05 -0800599
Peer Chen6f2cbc72012-03-13 11:12:39 +0800600/*
601 * Parse the given string and find sdram parameter and value in config
602 * file. If match, call the corresponding function set the sdram parameter.
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 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800609static int
610parse_sdram_param(build_image_context *context, parse_token token, char *rest)
611{
612 u_int32_t value;
613 field_item *field;
614 u_int32_t index;
615
616 assert(context != NULL);
617 assert(rest != NULL);
618
619 /* Parse the index. */
620 rest = parse_u32(rest, &index);
621 if (rest == NULL)
622 return 1;
623
624 /* Parse the closing bracket. */
625 if (*rest != ']')
626 return 1;
627 rest++;
628
629 /* Parse the following '.' */
630 if (*rest != '.')
631 return 1;
632 rest++;
633
634 /* Parse the field name. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800635 rest = parse_field_name(rest, g_soc_config->sdram_field_table, &field);
636
Peer Chen3a834ed2011-03-04 09:30:05 -0800637 if (rest == NULL)
638 return 1;
639
640 /* Parse the equals sign.*/
641 if (*rest != '=')
642 return 1;
643 rest++;
644
645 /* Parse the value based on the field table. */
646 rest = parse_field_value(context, rest, field, &value);
647 if (rest == NULL)
648 return 1;
649
650 /* Store the result. */
Penny Chiu5f4e2a32012-12-21 21:17:37 +0800651 return g_soc_config->set_sdram_param(context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800652 index,
653 field->token,
654 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800655}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800656
657/*
658 * Compare the given string with item listed in table.
659 * Execute the proper process function if match.
660 *
661 * @param context The main context pointer
662 * @param str String to parse
663 * @param simple_parse Simple parse flag
664 * @return 0 and 1 for success and failure
665 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500666static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800667process_statement(build_image_context *context,
668 char *str,
669 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500670{
671 int i;
672 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800673 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500674
Peer Chen6f2cbc72012-03-13 11:12:39 +0800675 if (simple_parse == 0)
676 cfg_parse_item = s_top_level_items;
677 else
678 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500679
Peer Chen6f2cbc72012-03-13 11:12:39 +0800680 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
681 if (!strncmp(cfg_parse_item[i].prefix, str,
682 strlen(cfg_parse_item[i].prefix))) {
683 rest = str + strlen(cfg_parse_item[i].prefix);
684
685 return cfg_parse_item[i].process(context,
686 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500687 rest);
688 }
689 }
690
691 /* If this point was reached, there was a processing error. */
692 return 1;
693}
694
Peer Chen6f2cbc72012-03-13 11:12:39 +0800695/*
696 * The main function parse the config file.
697 *
698 * @param context The main context pointer
699 * @param simple_parse Simple parse flag
700 */
701void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500702{
703 char buffer[MAX_BUFFER];
704 int space = 0;
Stephen Warrenacbfad42013-01-17 14:41:28 -0700705 int current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800706 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500707 u_int8_t comment = 0;
708 u_int8_t string = 0;
709 u_int8_t equal_encounter = 0;
710
711 assert(context != NULL);
712 assert(context->config_file != NULL);
713
Peer Chen6f2cbc72012-03-13 11:12:39 +0800714 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500715 if (space >= (MAX_BUFFER-1)) {
716 /* if we exceeded the max buffer size, it is likely
717 due to a missing semi-colon at the end of a line */
718 printf("Config file parsing error!");
719 exit(1);
720 }
721
722 /* Handle failure to complete "//" comment token.
723 Insert the '/' into the busffer and proceed with
724 processing the current character. */
725 if (c_eol_comment_start && current != '/') {
726 c_eol_comment_start = 0;
727 buffer[space++] = '/';
728 }
729
730 switch (current) {
731 case '\"': /* " indicates start or end of a string */
732 if (!comment) {
733 string ^= 1;
734 buffer[space++] = current;
735 }
736 break;
737 case ';':
738 if (!string && !comment) {
739 buffer[space++] = '\0';
740
Peer Chen6f2cbc72012-03-13 11:12:39 +0800741 if (process_statement(context,
742 buffer,
743 simple_parse))
744 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500745 space = 0;
746 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800747 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500748 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500749 break;
750
751 case '/':
752 if (!string && !comment) {
753 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800754 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500755 comment = 1;
756 c_eol_comment_start = 0;
757 } else {
758 /* Potential start of eol comment. */
759 c_eol_comment_start = 1;
760 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800761 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500762 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500763 break;
764
765 /* ignore whitespace. uses fallthrough */
766 case '\n':
767 case '\r': /* carriage returns end comments */
768 string = 0;
769 comment = 0;
770 c_eol_comment_start = 0;
771 case ' ':
772 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800773 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500774 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500775 break;
776
777 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800778 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500779 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800780 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500781 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500782 break;
783
784 default:
785 if (!comment) {
786 buffer[space++] = current;
787 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800788 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500789 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800790 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500791 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500792 }
793 }
794 break;
795 }
796 }
797
798 return;
799
800 error:
801 printf("Error parsing: %s\n", buffer);
802 exit(1);
803}