blob: a89290b072931575aba0b1dd80457ca8ea94cbed [file] [log] [blame]
Peer Chen8d782ee2011-01-18 21:34:18 -05001/**
Peer Chen6f2cbc72012-03-13 11:12:39 +08002 * Copyright (c) 2012 NVIDIA Corporation. All rights reserved.
Peer Chen8d782ee2011-01-18 21:34:18 -05003 *
4 * See file CREDITS for list of people who contributed to this
5 * project.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23/*
24 * parse.c - Parsing support for the cbootimage tool
25 */
26
Peer Chen6f2cbc72012-03-13 11:12:39 +080027#include <ctype.h>
Peer Chen8d782ee2011-01-18 21:34:18 -050028#include "parse.h"
29#include "cbootimage.h"
30#include "data_layout.h"
31#include "crypto.h"
32#include "set.h"
33
34/*
35 * Function prototypes
36 *
37 * ParseXXX() parses XXX in the input
38 * SetXXX() sets state based on the parsing results but does not perform
39 * any parsing of its own
40 * A ParseXXX() function may call other parse functions and set functions.
41 * A SetXXX() function may not call any parseing functions.
42 */
43
Peer Chen6f2cbc72012-03-13 11:12:39 +080044static int
45set_array(build_image_context *context,
46 u_int32_t index,
47 parse_token token,
48 u_int32_t value);
49static char *parse_u32(char *str, u_int32_t *val);
50static char *parse_u8(char *str, u_int32_t *val);
51static char *parse_filename(char *str, char *name, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080052static char *parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +080053 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -080054 enum_item *table,
55 u_int32_t *val);
56static char
57*parse_field_name(char *rest, field_item *field_table, field_item **field);
58static char
Anton Staafe517a4f2011-03-14 12:28:06 -070059*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -080060 char *rest,
61 field_item *field,
62 u_int32_t *value);
Peer Chen8d782ee2011-01-18 21:34:18 -050063static int
64parse_array(build_image_context *context, parse_token token, char *rest);
65static int
66parse_bootloader(build_image_context *context, parse_token token, char *rest);
67static int
68parse_value_u32(build_image_context *context, parse_token token, char *rest);
69static int
70parse_bct_file(build_image_context *context, parse_token token, char *rest);
Peer Chen8d782ee2011-01-18 21:34:18 -050071static char
Peer Chen6f2cbc72012-03-13 11:12:39 +080072*parse_end_state(char *str, char *uname, int chars_remaining);
Peer Chen7557d9b2011-02-24 09:29:23 -080073static int
74parse_dev_param(build_image_context *context, parse_token token, char *rest);
Peer Chen3a834ed2011-03-04 09:30:05 -080075static int
76parse_sdram_param(build_image_context *context, parse_token token, char *rest);
Peer Chen7557d9b2011-02-24 09:29:23 -080077
Peer Chen6f2cbc72012-03-13 11:12:39 +080078static int process_statement(build_image_context *context,
79 char *str,
80 u_int8_t simple_parse);
Peer Chen8d782ee2011-01-18 21:34:18 -050081
Peer Chen6f2cbc72012-03-13 11:12:39 +080082static parse_item parse_simple_items[] =
Peer Chen7557d9b2011-02-24 09:29:23 -080083{
Peer Chen6f2cbc72012-03-13 11:12:39 +080084 { "Bctfile=", token_bct_file, parse_bct_file },
85 { "BootLoader=", token_bootloader, parse_bootloader },
86 { "Redundancy=", token_redundancy, parse_value_u32 },
87 { "Bctcopy=", token_bct_copy, parse_value_u32 },
88 { "Version=", token_version, parse_value_u32 },
89 { NULL, 0, NULL } /* Must be last */
Peer Chen7557d9b2011-02-24 09:29:23 -080090};
91
Peer Chen6f2cbc72012-03-13 11:12:39 +080092static parse_item s_top_level_items[] = {
Peer Chen053d5782011-03-03 10:12:58 -080093 { "Bctfile=", token_bct_file, parse_bct_file },
94 { "Attribute=", token_attribute, parse_value_u32 },
95 { "Attribute[", token_attribute, parse_array },
96 { "PageSize=", token_page_size, parse_value_u32 },
97 { "BlockSize=", token_block_size, parse_value_u32 },
98 { "PartitionSize=", token_partition_size, parse_value_u32 },
99 { "DevType[", token_dev_type, parse_array },
100 { "DeviceParam[", token_dev_param, parse_dev_param },
Peer Chen3a834ed2011-03-04 09:30:05 -0800101 { "SDRAM[", token_sdram, parse_sdram_param },
Peer Chen053d5782011-03-03 10:12:58 -0800102 { "BootLoader=", token_bootloader, parse_bootloader },
103 { "Redundancy=", token_redundancy, parse_value_u32 },
Peer Chen56f40482011-07-27 02:59:41 -0400104 { "Bctcopy=", token_bct_copy, parse_value_u32 },
Peer Chen053d5782011-03-03 10:12:58 -0800105 { "Version=", token_version, parse_value_u32 },
Peer Chen8d782ee2011-01-18 21:34:18 -0500106 { NULL, 0, NULL } /* Must be last */
107};
108
109/* Macro to simplify parser code a bit. */
110#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
111
Peer Chen6f2cbc72012-03-13 11:12:39 +0800112/*
113 * Parse the given string and find the u32 dec/hex number.
114 *
115 * @param str String to parse
116 * @param val Returns value that was parsed
117 * @return the remainder of the string after the number was parsed
118 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500119static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800120parse_u32(char *str, u_int32_t *val)
Peer Chen8d782ee2011-01-18 21:34:18 -0500121{
122 u_int32_t value = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800123 u_int32_t digit;
Peer Chen8d782ee2011-01-18 21:34:18 -0500124
Peer Chen6f2cbc72012-03-13 11:12:39 +0800125 while (*str == '0')
126 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500127
Peer Chen6f2cbc72012-03-13 11:12:39 +0800128 if (tolower(*str) == 'x') {
129 str++;
130 while (isxdigit(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500131 value *= 16;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800132 digit = tolower(*str);
133 value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
134 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500135 }
136 } else {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800137 while (*str >= '0' && *str <= '9') {
138 value = value*10 + (*str - '0');
139 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500140 }
141 }
142 *val = value;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800143 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500144}
145
Peer Chen6f2cbc72012-03-13 11:12:39 +0800146/*
147 * Parse the given string and find the u8 dec/hex number.
148 *
149 * @param str String to parse
150 * @param val Returns value that was parsed
151 * @return the remainder of the string after the number was parsed
152 */
153static char *
154parse_u8(char *str, u_int32_t *val)
Peer Chen7557d9b2011-02-24 09:29:23 -0800155{
156 char *retval;
157
Peer Chen6f2cbc72012-03-13 11:12:39 +0800158 retval = parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800159
160 if (*val > 0xff) {
161 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
162 printf(" Parsed value = %d. Remaining text = %s\n",
163 *val, retval);
164 }
165
166 return retval;
167}
168
169
Peer Chen6f2cbc72012-03-13 11:12:39 +0800170/*
171 * Parse the given string and find the file name then
172 * return the rest of the string.
173 *
174 * @param str String to parse
175 * @param name Returns the filename that was parsed
176 * @param chars_remaining The maximum length of filename
177 * @return the remainder of the string after the name was parsed
178 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500179static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800180parse_filename(char *str, char *name, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500181{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800182 /*
183 * Check if the filename buffer is out of space, preserving one
184 * character to null terminate the string.
185 */
186 while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
187
Peer Chen8d782ee2011-01-18 21:34:18 -0500188 chars_remaining--;
189
190 if (chars_remaining < 1)
191 return NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800192 *name++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500193 }
194
195 /* Null terminate the filename. */
196 *name = '\0';
197
Peer Chen6f2cbc72012-03-13 11:12:39 +0800198 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500199}
200
Peer Chen6f2cbc72012-03-13 11:12:39 +0800201/*
202 * Parse the given string and find the match field name listed
203 * in field table.
204 *
205 * @param rest String to parse
206 * @param field_table The field table to parse
207 * @param field Returns the field item that was parsed
208 * @return NULL or the remainder of the string after the field item was parsed
209 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800210static char
211*parse_field_name(char *rest, field_item *field_table, field_item **field)
212{
213 u_int32_t i;
214 u_int32_t field_name_len = 0;
215
216 assert(field_table != NULL);
217 assert(rest != NULL);
218 assert(field != NULL);
219
Peer Chen6f2cbc72012-03-13 11:12:39 +0800220 while (rest[field_name_len] != '=')
Peer Chen7557d9b2011-02-24 09:29:23 -0800221 field_name_len++;
222
223 /* Parse the field name. */
224 for (i = 0; field_table[i].name != NULL; i++) {
225 if ((strlen(field_table[i].name) == field_name_len) &&
226 !strncmp(field_table[i].name,
227 rest,
228 field_name_len)) {
229
230 *field = &(field_table[i]);
231 rest = rest + field_name_len;
232 return rest;
233 }
234 }
235
236 /* Field wasn't found or a parse error occurred. */
237 return NULL;
238}
239
Peer Chen6f2cbc72012-03-13 11:12:39 +0800240/*
241 * Parse the value based on the field table
242 *
243 * @param context The main context pointer
244 * @param rest String to parse
245 * @param field Field item to parse
246 * @param value Returns the value that was parsed
247 * @return the remainder of the string after the value was parsed
248 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800249static char
Peer Chen6f2cbc72012-03-13 11:12:39 +0800250*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -0800251 char *rest,
252 field_item *field,
253 u_int32_t *value)
254{
255 assert(rest != NULL);
256 assert(field != NULL);
257 assert((field->type != field_type_enum)
258 || (field->enum_table != NULL));
259
260 switch (field->type) {
261 case field_type_enum:
262 rest = parse_enum(context, rest, field->enum_table, value);
263 break;
264
265 case field_type_u32:
266 rest = parse_u32(rest, value);
267 break;
268
269 case field_type_u8:
270 rest = parse_u8(rest, value);
271 break;
272
273 default:
274 printf("Unexpected field type %d at line %d\n",
275 field->type, __LINE__);
276 rest = NULL;
277 break;
278 }
279
280 return rest;
281}
282
Peer Chen6f2cbc72012-03-13 11:12:39 +0800283/*
284 * Parse the given string and find the match enum item listed
285 * in table.
286 *
287 * @param context The main context pointer
288 * @param str String to parse
289 * @param table Enum item table to parse
290 * @param value Returns the value that was parsed
291 * @return the remainder of the string after the item was parsed
292 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800293static char *
294parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800295 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800296 enum_item *table,
297 u_int32_t *val)
298{
299 int i;
300 char *rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800301
302 for (i = 0; table[i].name != NULL; i++) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800303 if (!strncmp(table[i].name, str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800304 strlen(table[i].name))) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800305 *val = table[i].value;
306 rest = str + strlen(table[i].name);
307 return rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800308 }
309 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800310 return parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800311
312}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800313
Peer Chen8d782ee2011-01-18 21:34:18 -0500314/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800315 * Parse the given string and find the bootloader file name, load address and
316 * entry point information then call set_bootloader function.
317 *
318 * @param context The main context pointer
319 * @param token The parse token value
320 * @param rest String to parse
321 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500322 */
323static int parse_bootloader(build_image_context *context,
324 parse_token token,
325 char *rest)
326{
327 char filename[MAX_BUFFER];
328 char e_state[MAX_STR_LEN];
329 u_int32_t load_addr;
330 u_int32_t entry_point;
331
332 assert(context != NULL);
333 assert(rest != NULL);
334
Peer Chen7557d9b2011-02-24 09:29:23 -0800335 if (context->generate_bct != 0)
336 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500337 /* Parse the file name. */
338 rest = parse_filename(rest, filename, MAX_BUFFER);
339 if (rest == NULL)
340 return 1;
341
342 PARSE_COMMA(1);
343
344 /* Parse the load address. */
345 rest = parse_u32(rest, &load_addr);
346 if (rest == NULL)
347 return 1;
348
349 PARSE_COMMA(1);
350
351 /* Parse the entry point. */
352 rest = parse_u32(rest, &entry_point);
353 if (rest == NULL)
354 return 1;
355
356 PARSE_COMMA(1);
357
358 /* Parse the end state. */
359 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
360 if (rest == NULL)
361 return 1;
362 if (strncmp(e_state, "Complete", strlen("Complete")))
363 return 1;
364
365 /* Parsing has finished - set the bootloader */
366 return set_bootloader(context, filename, load_addr, entry_point);
367}
368
369/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800370 * Parse the given string and find the array items in config file.
371 *
372 * @param context The main context pointer
373 * @param token The parse token value
374 * @param rest String to parse
375 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500376 */
377static int
378parse_array(build_image_context *context, parse_token token, char *rest)
379{
380 u_int32_t index;
381 u_int32_t value;
382
383 assert(context != NULL);
384 assert(rest != NULL);
385
386 /* Parse the index. */
387 rest = parse_u32(rest, &index);
388 if (rest == NULL)
389 return 1;
390
391 /* Parse the closing bracket. */
392 if (*rest != ']')
393 return 1;
394 rest++;
395
396 /* Parse the equals sign.*/
397 if (*rest != '=')
398 return 1;
399 rest++;
400
401 /* Parse the value based on the field table. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800402 switch (token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800403 case token_attribute:
404 rest = parse_u32(rest, &value);
405 break;
406 case token_dev_type:
Peer Chen6f2cbc72012-03-13 11:12:39 +0800407 rest = parse_enum(context,
408 rest,
409 s_devtype_table_t20,
410 &value);
Peer Chen7557d9b2011-02-24 09:29:23 -0800411 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500412
Peer Chen7557d9b2011-02-24 09:29:23 -0800413 default:
414 /* Unknown token */
415 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500416 }
417
418 if (rest == NULL)
419 return 1;
420
421 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800422 return set_array(context, index, token, value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500423}
424
425/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800426 * Call hw interface to set the value for array item in bct such as device
427 * type and bootloader attribute.
428 *
429 * @param context The main context pointer
430 * @param index The index for array
431 * @param token The parse token value
432 * @param value The value to set
433 * @return 0 and -ENODATA for success and failure
434 */
435
436static int
437set_array(build_image_context *context,
438 u_int32_t index,
439 parse_token token,
440 u_int32_t value)
441{
442 int err = 0;
443
444 assert(context != NULL);
445
446 switch (token) {
447 case token_attribute:
448 err = g_bct_parse_interf->setbl_param(index,
449 token_bl_attribute,
450 &value,
451 context->bct);
452 break;
453 case token_dev_type:
454 err = g_bct_parse_interf->set_dev_param(context,
455 index,
456 token_dev_type,
457 value);
458 break;
459 default:
460 break;
461 }
462 return err;
463}
464
465/*
466 * General handler for setting u_int32_t values in config files.
467 *
468 * @param context The main context pointer
469 * @param token The parse token value
470 * @param rest String to parse
471 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500472 */
473static int parse_value_u32(build_image_context *context,
474 parse_token token,
475 char *rest)
476{
477 u_int32_t value;
478
479 assert(context != NULL);
480 assert(rest != NULL);
481
482 rest = parse_u32(rest, &value);
483 if (rest == NULL)
484 return 1;
485
486 return context_set_value(context, token, value);
487}
488
Peer Chen6f2cbc72012-03-13 11:12:39 +0800489/*
490 * Parse the given string and find the bct file name.
491 *
492 * @param context The main context pointer
493 * @param token The parse token value
494 * @param rest String to parse
495 * @return 0 and 1 for success and failure
496 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500497static int
498parse_bct_file(build_image_context *context, parse_token token, char *rest)
499{
500 char filename[MAX_BUFFER];
501
502 assert(context != NULL);
503 assert(rest != NULL);
504
505 /* Parse the file name. */
506 rest = parse_filename(rest, filename, MAX_BUFFER);
507 if (rest == NULL)
508 return 1;
509
510 /* Parsing has finished - set the bctfile */
511 context->bct_filename = filename;
512 /* Read the bct file to buffer */
513 read_bct_file(context);
Peer Chen6f2cbc72012-03-13 11:12:39 +0800514 update_context(context);
Peer Chen8d782ee2011-01-18 21:34:18 -0500515 return 0;
516}
517
518static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800519parse_end_state(char *str, char *uname, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500520{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800521 while (isalpha(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500522
Peer Chen6f2cbc72012-03-13 11:12:39 +0800523 *uname++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500524 if (--chars_remaining < 0)
525 return NULL;
526 }
527 *uname = '\0';
Peer Chen6f2cbc72012-03-13 11:12:39 +0800528 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500529}
530
Peer Chen6f2cbc72012-03-13 11:12:39 +0800531/*
532 * Parse the given string and find device parameter listed in device table
533 * and value for this device parameter. If match, call the corresponding
534 * function in the table to set device parameter.
535 *
536 * @param context The main context pointer
537 * @param token The parse token value
538 * @param rest String to parse
539 * @return 0 and 1 for success and failure
540 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800541static int
542parse_dev_param(build_image_context *context, parse_token token, char *rest)
543{
544 u_int32_t i;
545 u_int32_t value;
546 field_item *field;
547 u_int32_t index;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800548 parse_subfield_item *device_type_table;
Peer Chen7557d9b2011-02-24 09:29:23 -0800549 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
Peer Chen6f2cbc72012-03-13 11:12:39 +0800554 if (context->boot_data_version == NVBOOT_BOOTDATA_VERSION(3, 1))
555 device_type_table = s_device_type_table_t30;
556 else
557 device_type_table = s_device_type_table_t20;
Peer Chen7557d9b2011-02-24 09:29:23 -0800558 /* Parse the index. */
559 rest = parse_u32(rest, &index);
560 if (rest == NULL)
561 return 1;
562
563 /* Parse the closing bracket. */
564 if (*rest != ']')
565 return 1;
566 rest++;
567
568 /* Parse the following '.' */
569 if (*rest != '.')
570 return 1;
571 rest++;
572
573 /* Parse the device name. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800574 for (i = 0; device_type_table[i].prefix != NULL; i++) {
575 if (!strncmp(device_type_table[i].prefix,
576 rest, strlen(device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800577
Peer Chen6f2cbc72012-03-13 11:12:39 +0800578 device_item = &(device_type_table[i]);
579 rest = rest + strlen(device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800580
581 /* Parse the field name. */
582 rest = parse_field_name(rest,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800583 device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800584 &field);
585 if (rest == NULL)
586 return 1;
587
588 /* Parse the equals sign.*/
589 if (*rest != '=')
590 return 1;
591 rest++;
592
593 /* Parse the value based on the field table. */
594 rest = parse_field_value(context, rest, field, &value);
595 if (rest == NULL)
596 return 1;
597 return device_item->process(context,
598 index, field->token, value);
599 }
600 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800601 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800602}
Peer Chen3a834ed2011-03-04 09:30:05 -0800603
Peer Chen6f2cbc72012-03-13 11:12:39 +0800604/*
605 * Parse the given string and find sdram parameter and value in config
606 * file. If match, call the corresponding function set the sdram parameter.
607 *
608 * @param context The main context pointer
609 * @param token The parse token value
610 * @param rest String to parse
611 * @return 0 and 1 for success and failure
612 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800613static int
614parse_sdram_param(build_image_context *context, parse_token token, char *rest)
615{
616 u_int32_t value;
617 field_item *field;
618 u_int32_t index;
619
620 assert(context != NULL);
621 assert(rest != NULL);
622
623 /* Parse the index. */
624 rest = parse_u32(rest, &index);
625 if (rest == NULL)
626 return 1;
627
628 /* Parse the closing bracket. */
629 if (*rest != ']')
630 return 1;
631 rest++;
632
633 /* Parse the following '.' */
634 if (*rest != '.')
635 return 1;
636 rest++;
637
638 /* Parse the field name. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800639 if (context->boot_data_version == NVBOOT_BOOTDATA_VERSION(3, 1))
640 rest = parse_field_name(rest, s_sdram_field_table_t30, &field);
641 else
642 rest = parse_field_name(rest, s_sdram_field_table_t20, &field);
Peer Chen3a834ed2011-03-04 09:30:05 -0800643 if (rest == NULL)
644 return 1;
645
646 /* Parse the equals sign.*/
647 if (*rest != '=')
648 return 1;
649 rest++;
650
651 /* Parse the value based on the field table. */
652 rest = parse_field_value(context, rest, field, &value);
653 if (rest == NULL)
654 return 1;
655
656 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800657 return g_bct_parse_interf->set_sdram_param(context,
658 index,
659 field->token,
660 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800661}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800662
663/*
664 * Compare the given string with item listed in table.
665 * Execute the proper process function if match.
666 *
667 * @param context The main context pointer
668 * @param str String to parse
669 * @param simple_parse Simple parse flag
670 * @return 0 and 1 for success and failure
671 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500672static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800673process_statement(build_image_context *context,
674 char *str,
675 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500676{
677 int i;
678 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800679 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500680
Peer Chen6f2cbc72012-03-13 11:12:39 +0800681 if (simple_parse == 0)
682 cfg_parse_item = s_top_level_items;
683 else
684 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500685
Peer Chen6f2cbc72012-03-13 11:12:39 +0800686 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
687 if (!strncmp(cfg_parse_item[i].prefix, str,
688 strlen(cfg_parse_item[i].prefix))) {
689 rest = str + strlen(cfg_parse_item[i].prefix);
690
691 return cfg_parse_item[i].process(context,
692 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500693 rest);
694 }
695 }
696
697 /* If this point was reached, there was a processing error. */
698 return 1;
699}
700
Peer Chen6f2cbc72012-03-13 11:12:39 +0800701/*
702 * The main function parse the config file.
703 *
704 * @param context The main context pointer
705 * @param simple_parse Simple parse flag
706 */
707void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500708{
709 char buffer[MAX_BUFFER];
710 int space = 0;
711 char current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800712 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500713 u_int8_t comment = 0;
714 u_int8_t string = 0;
715 u_int8_t equal_encounter = 0;
716
717 assert(context != NULL);
718 assert(context->config_file != NULL);
719
Peer Chen6f2cbc72012-03-13 11:12:39 +0800720 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500721 if (space >= (MAX_BUFFER-1)) {
722 /* if we exceeded the max buffer size, it is likely
723 due to a missing semi-colon at the end of a line */
724 printf("Config file parsing error!");
725 exit(1);
726 }
727
728 /* Handle failure to complete "//" comment token.
729 Insert the '/' into the busffer and proceed with
730 processing the current character. */
731 if (c_eol_comment_start && current != '/') {
732 c_eol_comment_start = 0;
733 buffer[space++] = '/';
734 }
735
736 switch (current) {
737 case '\"': /* " indicates start or end of a string */
738 if (!comment) {
739 string ^= 1;
740 buffer[space++] = current;
741 }
742 break;
743 case ';':
744 if (!string && !comment) {
745 buffer[space++] = '\0';
746
Peer Chen6f2cbc72012-03-13 11:12:39 +0800747 if (process_statement(context,
748 buffer,
749 simple_parse))
750 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500751 space = 0;
752 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800753 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500754 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500755 break;
756
757 case '/':
758 if (!string && !comment) {
759 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800760 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500761 comment = 1;
762 c_eol_comment_start = 0;
763 } else {
764 /* Potential start of eol comment. */
765 c_eol_comment_start = 1;
766 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800767 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500768 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500769 break;
770
771 /* ignore whitespace. uses fallthrough */
772 case '\n':
773 case '\r': /* carriage returns end comments */
774 string = 0;
775 comment = 0;
776 c_eol_comment_start = 0;
777 case ' ':
778 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800779 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500780 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500781 break;
782
783 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800784 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500785 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800786 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500787 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500788 break;
789
790 default:
791 if (!comment) {
792 buffer[space++] = current;
793 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800794 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500795 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800796 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500797 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500798 }
799 }
800 break;
801 }
802 }
803
804 return;
805
806 error:
807 printf("Error parsing: %s\n", buffer);
808 exit(1);
809}