blob: 5c074d5d588253961ca6b313013032813511f4c2 [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,
408 s_devtype_table_t20,
409 &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:
447 err = g_bct_parse_interf->setbl_param(index,
448 token_bl_attribute,
449 &value,
450 context->bct);
451 break;
452 case token_dev_type:
453 err = g_bct_parse_interf->set_dev_param(context,
454 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 */
512 read_bct_file(context);
Peer Chen6f2cbc72012-03-13 11:12:39 +0800513 update_context(context);
Peer Chen8d782ee2011-01-18 21:34:18 -0500514 return 0;
515}
516
517static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800518parse_end_state(char *str, char *uname, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500519{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800520 while (isalpha(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500521
Peer Chen6f2cbc72012-03-13 11:12:39 +0800522 *uname++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500523 if (--chars_remaining < 0)
524 return NULL;
525 }
526 *uname = '\0';
Peer Chen6f2cbc72012-03-13 11:12:39 +0800527 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500528}
529
Peer Chen6f2cbc72012-03-13 11:12:39 +0800530/*
531 * Parse the given string and find device parameter listed in device table
532 * and value for this device parameter. If match, call the corresponding
533 * function in the table to set device parameter.
534 *
535 * @param context The main context pointer
536 * @param token The parse token value
537 * @param rest String to parse
538 * @return 0 and 1 for success and failure
539 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800540static int
541parse_dev_param(build_image_context *context, parse_token token, char *rest)
542{
543 u_int32_t i;
544 u_int32_t value;
545 field_item *field;
546 u_int32_t index;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800547 parse_subfield_item *device_type_table;
Peer Chen7557d9b2011-02-24 09:29:23 -0800548 parse_subfield_item *device_item = NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800549
Peer Chen7557d9b2011-02-24 09:29:23 -0800550 assert(context != NULL);
551 assert(rest != NULL);
552
Peer Chen6f2cbc72012-03-13 11:12:39 +0800553 if (context->boot_data_version == NVBOOT_BOOTDATA_VERSION(3, 1))
554 device_type_table = s_device_type_table_t30;
555 else
556 device_type_table = s_device_type_table_t20;
Peer Chen7557d9b2011-02-24 09:29:23 -0800557 /* Parse the index. */
558 rest = parse_u32(rest, &index);
559 if (rest == NULL)
560 return 1;
561
562 /* Parse the closing bracket. */
563 if (*rest != ']')
564 return 1;
565 rest++;
566
567 /* Parse the following '.' */
568 if (*rest != '.')
569 return 1;
570 rest++;
571
572 /* Parse the device name. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800573 for (i = 0; device_type_table[i].prefix != NULL; i++) {
574 if (!strncmp(device_type_table[i].prefix,
575 rest, strlen(device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800576
Peer Chen6f2cbc72012-03-13 11:12:39 +0800577 device_item = &(device_type_table[i]);
578 rest = rest + strlen(device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800579
580 /* Parse the field name. */
581 rest = parse_field_name(rest,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800582 device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800583 &field);
584 if (rest == NULL)
585 return 1;
586
587 /* Parse the equals sign.*/
588 if (*rest != '=')
589 return 1;
590 rest++;
591
592 /* Parse the value based on the field table. */
593 rest = parse_field_value(context, rest, field, &value);
594 if (rest == NULL)
595 return 1;
596 return device_item->process(context,
597 index, field->token, value);
598 }
599 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800600 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800601}
Peer Chen3a834ed2011-03-04 09:30:05 -0800602
Peer Chen6f2cbc72012-03-13 11:12:39 +0800603/*
604 * Parse the given string and find sdram parameter and value in config
605 * file. If match, call the corresponding function set the sdram parameter.
606 *
607 * @param context The main context pointer
608 * @param token The parse token value
609 * @param rest String to parse
610 * @return 0 and 1 for success and failure
611 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800612static int
613parse_sdram_param(build_image_context *context, parse_token token, char *rest)
614{
615 u_int32_t value;
616 field_item *field;
617 u_int32_t index;
618
619 assert(context != NULL);
620 assert(rest != NULL);
621
622 /* Parse the index. */
623 rest = parse_u32(rest, &index);
624 if (rest == NULL)
625 return 1;
626
627 /* Parse the closing bracket. */
628 if (*rest != ']')
629 return 1;
630 rest++;
631
632 /* Parse the following '.' */
633 if (*rest != '.')
634 return 1;
635 rest++;
636
637 /* Parse the field name. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800638 if (context->boot_data_version == NVBOOT_BOOTDATA_VERSION(3, 1))
639 rest = parse_field_name(rest, s_sdram_field_table_t30, &field);
640 else
641 rest = parse_field_name(rest, s_sdram_field_table_t20, &field);
Peer Chen3a834ed2011-03-04 09:30:05 -0800642 if (rest == NULL)
643 return 1;
644
645 /* Parse the equals sign.*/
646 if (*rest != '=')
647 return 1;
648 rest++;
649
650 /* Parse the value based on the field table. */
651 rest = parse_field_value(context, rest, field, &value);
652 if (rest == NULL)
653 return 1;
654
655 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800656 return g_bct_parse_interf->set_sdram_param(context,
657 index,
658 field->token,
659 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800660}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800661
662/*
663 * Compare the given string with item listed in table.
664 * Execute the proper process function if match.
665 *
666 * @param context The main context pointer
667 * @param str String to parse
668 * @param simple_parse Simple parse flag
669 * @return 0 and 1 for success and failure
670 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500671static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800672process_statement(build_image_context *context,
673 char *str,
674 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500675{
676 int i;
677 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800678 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500679
Peer Chen6f2cbc72012-03-13 11:12:39 +0800680 if (simple_parse == 0)
681 cfg_parse_item = s_top_level_items;
682 else
683 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500684
Peer Chen6f2cbc72012-03-13 11:12:39 +0800685 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
686 if (!strncmp(cfg_parse_item[i].prefix, str,
687 strlen(cfg_parse_item[i].prefix))) {
688 rest = str + strlen(cfg_parse_item[i].prefix);
689
690 return cfg_parse_item[i].process(context,
691 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500692 rest);
693 }
694 }
695
696 /* If this point was reached, there was a processing error. */
697 return 1;
698}
699
Peer Chen6f2cbc72012-03-13 11:12:39 +0800700/*
701 * The main function parse the config file.
702 *
703 * @param context The main context pointer
704 * @param simple_parse Simple parse flag
705 */
706void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500707{
708 char buffer[MAX_BUFFER];
709 int space = 0;
710 char current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800711 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500712 u_int8_t comment = 0;
713 u_int8_t string = 0;
714 u_int8_t equal_encounter = 0;
715
716 assert(context != NULL);
717 assert(context->config_file != NULL);
718
Peer Chen6f2cbc72012-03-13 11:12:39 +0800719 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500720 if (space >= (MAX_BUFFER-1)) {
721 /* if we exceeded the max buffer size, it is likely
722 due to a missing semi-colon at the end of a line */
723 printf("Config file parsing error!");
724 exit(1);
725 }
726
727 /* Handle failure to complete "//" comment token.
728 Insert the '/' into the busffer and proceed with
729 processing the current character. */
730 if (c_eol_comment_start && current != '/') {
731 c_eol_comment_start = 0;
732 buffer[space++] = '/';
733 }
734
735 switch (current) {
736 case '\"': /* " indicates start or end of a string */
737 if (!comment) {
738 string ^= 1;
739 buffer[space++] = current;
740 }
741 break;
742 case ';':
743 if (!string && !comment) {
744 buffer[space++] = '\0';
745
Peer Chen6f2cbc72012-03-13 11:12:39 +0800746 if (process_statement(context,
747 buffer,
748 simple_parse))
749 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500750 space = 0;
751 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800752 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500753 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500754 break;
755
756 case '/':
757 if (!string && !comment) {
758 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800759 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500760 comment = 1;
761 c_eol_comment_start = 0;
762 } else {
763 /* Potential start of eol comment. */
764 c_eol_comment_start = 1;
765 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800766 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500767 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500768 break;
769
770 /* ignore whitespace. uses fallthrough */
771 case '\n':
772 case '\r': /* carriage returns end comments */
773 string = 0;
774 comment = 0;
775 c_eol_comment_start = 0;
776 case ' ':
777 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800778 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500779 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500780 break;
781
782 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800783 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500784 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800785 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500786 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500787 break;
788
789 default:
790 if (!comment) {
791 buffer[space++] = current;
792 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800793 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500794 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800795 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500796 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500797 }
798 }
799 break;
800 }
801 }
802
803 return;
804
805 error:
806 printf("Error parsing: %s\n", buffer);
807 exit(1);
808}