blob: 23bdf266163ccac7aab4e7b475594fe4a3d128a8 [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 },
Stephen Warrenfb4793a2012-05-16 14:38:17 -0600106 { "OdmData=", token_odm_data, parse_value_u32 },
Peer Chen8d782ee2011-01-18 21:34:18 -0500107 { NULL, 0, NULL } /* Must be last */
108};
109
110/* Macro to simplify parser code a bit. */
111#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
112
Peer Chen6f2cbc72012-03-13 11:12:39 +0800113/*
114 * Parse the given string and find the u32 dec/hex number.
115 *
116 * @param str String to parse
117 * @param val Returns value that was parsed
118 * @return the remainder of the string after the number was parsed
119 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500120static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800121parse_u32(char *str, u_int32_t *val)
Peer Chen8d782ee2011-01-18 21:34:18 -0500122{
123 u_int32_t value = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800124 u_int32_t digit;
Peer Chen8d782ee2011-01-18 21:34:18 -0500125
Peer Chen6f2cbc72012-03-13 11:12:39 +0800126 while (*str == '0')
127 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500128
Peer Chen6f2cbc72012-03-13 11:12:39 +0800129 if (tolower(*str) == 'x') {
130 str++;
131 while (isxdigit(*str)) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500132 value *= 16;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800133 digit = tolower(*str);
134 value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
135 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500136 }
137 } else {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800138 while (*str >= '0' && *str <= '9') {
139 value = value*10 + (*str - '0');
140 str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500141 }
142 }
143 *val = value;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800144 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500145}
146
Peer Chen6f2cbc72012-03-13 11:12:39 +0800147/*
148 * Parse the given string and find the u8 dec/hex number.
149 *
150 * @param str String to parse
151 * @param val Returns value that was parsed
152 * @return the remainder of the string after the number was parsed
153 */
154static char *
155parse_u8(char *str, u_int32_t *val)
Peer Chen7557d9b2011-02-24 09:29:23 -0800156{
157 char *retval;
158
Peer Chen6f2cbc72012-03-13 11:12:39 +0800159 retval = parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800160
161 if (*val > 0xff) {
162 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
163 printf(" Parsed value = %d. Remaining text = %s\n",
164 *val, retval);
165 }
166
167 return retval;
168}
169
170
Peer Chen6f2cbc72012-03-13 11:12:39 +0800171/*
172 * Parse the given string and find the file name then
173 * return the rest of the string.
174 *
175 * @param str String to parse
176 * @param name Returns the filename that was parsed
177 * @param chars_remaining The maximum length of filename
178 * @return the remainder of the string after the name was parsed
179 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500180static char *
Peer Chen6f2cbc72012-03-13 11:12:39 +0800181parse_filename(char *str, char *name, int chars_remaining)
Peer Chen8d782ee2011-01-18 21:34:18 -0500182{
Peer Chen6f2cbc72012-03-13 11:12:39 +0800183 /*
184 * Check if the filename buffer is out of space, preserving one
185 * character to null terminate the string.
186 */
187 while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
188
Peer Chen8d782ee2011-01-18 21:34:18 -0500189 chars_remaining--;
190
191 if (chars_remaining < 1)
192 return NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800193 *name++ = *str++;
Peer Chen8d782ee2011-01-18 21:34:18 -0500194 }
195
196 /* Null terminate the filename. */
197 *name = '\0';
198
Peer Chen6f2cbc72012-03-13 11:12:39 +0800199 return str;
Peer Chen8d782ee2011-01-18 21:34:18 -0500200}
201
Peer Chen6f2cbc72012-03-13 11:12:39 +0800202/*
203 * Parse the given string and find the match field name listed
204 * in field table.
205 *
206 * @param rest String to parse
207 * @param field_table The field table to parse
208 * @param field Returns the field item that was parsed
209 * @return NULL or the remainder of the string after the field item was parsed
210 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800211static char
212*parse_field_name(char *rest, field_item *field_table, field_item **field)
213{
214 u_int32_t i;
215 u_int32_t field_name_len = 0;
216
217 assert(field_table != NULL);
218 assert(rest != NULL);
219 assert(field != NULL);
220
Peer Chen6f2cbc72012-03-13 11:12:39 +0800221 while (rest[field_name_len] != '=')
Peer Chen7557d9b2011-02-24 09:29:23 -0800222 field_name_len++;
223
224 /* Parse the field name. */
225 for (i = 0; field_table[i].name != NULL; i++) {
226 if ((strlen(field_table[i].name) == field_name_len) &&
227 !strncmp(field_table[i].name,
228 rest,
229 field_name_len)) {
230
231 *field = &(field_table[i]);
232 rest = rest + field_name_len;
233 return rest;
234 }
235 }
236
237 /* Field wasn't found or a parse error occurred. */
238 return NULL;
239}
240
Peer Chen6f2cbc72012-03-13 11:12:39 +0800241/*
242 * Parse the value based on the field table
243 *
244 * @param context The main context pointer
245 * @param rest String to parse
246 * @param field Field item to parse
247 * @param value Returns the value that was parsed
248 * @return the remainder of the string after the value was parsed
249 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800250static char
Peer Chen6f2cbc72012-03-13 11:12:39 +0800251*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -0800252 char *rest,
253 field_item *field,
254 u_int32_t *value)
255{
256 assert(rest != NULL);
257 assert(field != NULL);
258 assert((field->type != field_type_enum)
259 || (field->enum_table != NULL));
260
261 switch (field->type) {
262 case field_type_enum:
263 rest = parse_enum(context, rest, field->enum_table, value);
264 break;
265
266 case field_type_u32:
267 rest = parse_u32(rest, value);
268 break;
269
270 case field_type_u8:
271 rest = parse_u8(rest, value);
272 break;
273
274 default:
275 printf("Unexpected field type %d at line %d\n",
276 field->type, __LINE__);
277 rest = NULL;
278 break;
279 }
280
281 return rest;
282}
283
Peer Chen6f2cbc72012-03-13 11:12:39 +0800284/*
285 * Parse the given string and find the match enum item listed
286 * in table.
287 *
288 * @param context The main context pointer
289 * @param str String to parse
290 * @param table Enum item table to parse
291 * @param value Returns the value that was parsed
292 * @return the remainder of the string after the item was parsed
293 */
Peer Chen7557d9b2011-02-24 09:29:23 -0800294static char *
295parse_enum(build_image_context *context,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800296 char *str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800297 enum_item *table,
298 u_int32_t *val)
299{
300 int i;
301 char *rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800302
303 for (i = 0; table[i].name != NULL; i++) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800304 if (!strncmp(table[i].name, str,
Peer Chen7557d9b2011-02-24 09:29:23 -0800305 strlen(table[i].name))) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800306 *val = table[i].value;
307 rest = str + strlen(table[i].name);
308 return rest;
Peer Chen7557d9b2011-02-24 09:29:23 -0800309 }
310 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800311 return parse_u32(str, val);
Peer Chen7557d9b2011-02-24 09:29:23 -0800312
313}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800314
Peer Chen8d782ee2011-01-18 21:34:18 -0500315/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800316 * Parse the given string and find the bootloader file name, load address and
317 * entry point information then call set_bootloader function.
318 *
319 * @param context The main context pointer
320 * @param token The parse token value
321 * @param rest String to parse
322 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500323 */
324static int parse_bootloader(build_image_context *context,
325 parse_token token,
326 char *rest)
327{
328 char filename[MAX_BUFFER];
329 char e_state[MAX_STR_LEN];
330 u_int32_t load_addr;
331 u_int32_t entry_point;
332
333 assert(context != NULL);
334 assert(rest != NULL);
335
Peer Chen7557d9b2011-02-24 09:29:23 -0800336 if (context->generate_bct != 0)
337 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500338 /* Parse the file name. */
339 rest = parse_filename(rest, filename, MAX_BUFFER);
340 if (rest == NULL)
341 return 1;
342
343 PARSE_COMMA(1);
344
345 /* Parse the load address. */
346 rest = parse_u32(rest, &load_addr);
347 if (rest == NULL)
348 return 1;
349
350 PARSE_COMMA(1);
351
352 /* Parse the entry point. */
353 rest = parse_u32(rest, &entry_point);
354 if (rest == NULL)
355 return 1;
356
357 PARSE_COMMA(1);
358
359 /* Parse the end state. */
360 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
361 if (rest == NULL)
362 return 1;
363 if (strncmp(e_state, "Complete", strlen("Complete")))
364 return 1;
365
366 /* Parsing has finished - set the bootloader */
367 return set_bootloader(context, filename, load_addr, entry_point);
368}
369
370/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800371 * Parse the given string and find the array items in config file.
372 *
373 * @param context The main context pointer
374 * @param token The parse token value
375 * @param rest String to parse
376 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500377 */
378static int
379parse_array(build_image_context *context, parse_token token, char *rest)
380{
381 u_int32_t index;
382 u_int32_t value;
383
384 assert(context != NULL);
385 assert(rest != NULL);
386
387 /* Parse the index. */
388 rest = parse_u32(rest, &index);
389 if (rest == NULL)
390 return 1;
391
392 /* Parse the closing bracket. */
393 if (*rest != ']')
394 return 1;
395 rest++;
396
397 /* Parse the equals sign.*/
398 if (*rest != '=')
399 return 1;
400 rest++;
401
402 /* Parse the value based on the field table. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800403 switch (token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800404 case token_attribute:
405 rest = parse_u32(rest, &value);
406 break;
407 case token_dev_type:
Peer Chen6f2cbc72012-03-13 11:12:39 +0800408 rest = parse_enum(context,
409 rest,
410 s_devtype_table_t20,
411 &value);
Peer Chen7557d9b2011-02-24 09:29:23 -0800412 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500413
Peer Chen7557d9b2011-02-24 09:29:23 -0800414 default:
415 /* Unknown token */
416 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500417 }
418
419 if (rest == NULL)
420 return 1;
421
422 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800423 return set_array(context, index, token, value);
Peer Chen8d782ee2011-01-18 21:34:18 -0500424}
425
426/*
Peer Chen6f2cbc72012-03-13 11:12:39 +0800427 * Call hw interface to set the value for array item in bct such as device
428 * type and bootloader attribute.
429 *
430 * @param context The main context pointer
431 * @param index The index for array
432 * @param token The parse token value
433 * @param value The value to set
434 * @return 0 and -ENODATA for success and failure
435 */
436
437static int
438set_array(build_image_context *context,
439 u_int32_t index,
440 parse_token token,
441 u_int32_t value)
442{
443 int err = 0;
444
445 assert(context != NULL);
446
447 switch (token) {
448 case token_attribute:
449 err = g_bct_parse_interf->setbl_param(index,
450 token_bl_attribute,
451 &value,
452 context->bct);
453 break;
454 case token_dev_type:
455 err = g_bct_parse_interf->set_dev_param(context,
456 index,
457 token_dev_type,
458 value);
459 break;
460 default:
461 break;
462 }
463 return err;
464}
465
466/*
467 * General handler for setting u_int32_t values in config files.
468 *
469 * @param context The main context pointer
470 * @param token The parse token value
471 * @param rest String to parse
472 * @return 0 and 1 for success and failure
Peer Chen8d782ee2011-01-18 21:34:18 -0500473 */
474static int parse_value_u32(build_image_context *context,
475 parse_token token,
476 char *rest)
477{
478 u_int32_t value;
479
480 assert(context != NULL);
481 assert(rest != NULL);
482
483 rest = parse_u32(rest, &value);
484 if (rest == NULL)
485 return 1;
486
487 return context_set_value(context, token, value);
488}
489
Peer Chen6f2cbc72012-03-13 11:12:39 +0800490/*
491 * Parse the given string and find the bct file name.
492 *
493 * @param context The main context pointer
494 * @param token The parse token value
495 * @param rest String to parse
496 * @return 0 and 1 for success and failure
497 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500498static int
499parse_bct_file(build_image_context *context, parse_token token, char *rest)
500{
501 char filename[MAX_BUFFER];
502
503 assert(context != NULL);
504 assert(rest != NULL);
505
506 /* Parse the file name. */
507 rest = parse_filename(rest, filename, MAX_BUFFER);
508 if (rest == NULL)
509 return 1;
510
511 /* Parsing has finished - set the bctfile */
512 context->bct_filename = filename;
513 /* Read the bct file to buffer */
514 read_bct_file(context);
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;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800549 parse_subfield_item *device_type_table;
Peer Chen7557d9b2011-02-24 09:29:23 -0800550 parse_subfield_item *device_item = NULL;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800551
Peer Chen7557d9b2011-02-24 09:29:23 -0800552 assert(context != NULL);
553 assert(rest != NULL);
554
Peer Chen6f2cbc72012-03-13 11:12:39 +0800555 if (context->boot_data_version == NVBOOT_BOOTDATA_VERSION(3, 1))
556 device_type_table = s_device_type_table_t30;
557 else
558 device_type_table = s_device_type_table_t20;
Peer Chen7557d9b2011-02-24 09:29:23 -0800559 /* Parse the index. */
560 rest = parse_u32(rest, &index);
561 if (rest == NULL)
562 return 1;
563
564 /* Parse the closing bracket. */
565 if (*rest != ']')
566 return 1;
567 rest++;
568
569 /* Parse the following '.' */
570 if (*rest != '.')
571 return 1;
572 rest++;
573
574 /* Parse the device name. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800575 for (i = 0; device_type_table[i].prefix != NULL; i++) {
576 if (!strncmp(device_type_table[i].prefix,
577 rest, strlen(device_type_table[i].prefix))) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800578
Peer Chen6f2cbc72012-03-13 11:12:39 +0800579 device_item = &(device_type_table[i]);
580 rest = rest + strlen(device_type_table[i].prefix);
Peer Chen7557d9b2011-02-24 09:29:23 -0800581
582 /* Parse the field name. */
583 rest = parse_field_name(rest,
Peer Chen6f2cbc72012-03-13 11:12:39 +0800584 device_type_table[i].field_table,
Peer Chen7557d9b2011-02-24 09:29:23 -0800585 &field);
586 if (rest == NULL)
587 return 1;
588
589 /* Parse the equals sign.*/
590 if (*rest != '=')
591 return 1;
592 rest++;
593
594 /* Parse the value based on the field table. */
595 rest = parse_field_value(context, rest, field, &value);
596 if (rest == NULL)
597 return 1;
598 return device_item->process(context,
599 index, field->token, value);
600 }
601 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800602 return 1;
Peer Chen7557d9b2011-02-24 09:29:23 -0800603}
Peer Chen3a834ed2011-03-04 09:30:05 -0800604
Peer Chen6f2cbc72012-03-13 11:12:39 +0800605/*
606 * Parse the given string and find sdram parameter and value in config
607 * file. If match, call the corresponding function set the sdram parameter.
608 *
609 * @param context The main context pointer
610 * @param token The parse token value
611 * @param rest String to parse
612 * @return 0 and 1 for success and failure
613 */
Peer Chen3a834ed2011-03-04 09:30:05 -0800614static int
615parse_sdram_param(build_image_context *context, parse_token token, char *rest)
616{
617 u_int32_t value;
618 field_item *field;
619 u_int32_t index;
620
621 assert(context != NULL);
622 assert(rest != NULL);
623
624 /* Parse the index. */
625 rest = parse_u32(rest, &index);
626 if (rest == NULL)
627 return 1;
628
629 /* Parse the closing bracket. */
630 if (*rest != ']')
631 return 1;
632 rest++;
633
634 /* Parse the following '.' */
635 if (*rest != '.')
636 return 1;
637 rest++;
638
639 /* Parse the field name. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800640 if (context->boot_data_version == NVBOOT_BOOTDATA_VERSION(3, 1))
641 rest = parse_field_name(rest, s_sdram_field_table_t30, &field);
642 else
643 rest = parse_field_name(rest, s_sdram_field_table_t20, &field);
Peer Chen3a834ed2011-03-04 09:30:05 -0800644 if (rest == NULL)
645 return 1;
646
647 /* Parse the equals sign.*/
648 if (*rest != '=')
649 return 1;
650 rest++;
651
652 /* Parse the value based on the field table. */
653 rest = parse_field_value(context, rest, field, &value);
654 if (rest == NULL)
655 return 1;
656
657 /* Store the result. */
Peer Chen6f2cbc72012-03-13 11:12:39 +0800658 return g_bct_parse_interf->set_sdram_param(context,
659 index,
660 field->token,
661 value);
Peer Chen3a834ed2011-03-04 09:30:05 -0800662}
Peer Chen6f2cbc72012-03-13 11:12:39 +0800663
664/*
665 * Compare the given string with item listed in table.
666 * Execute the proper process function if match.
667 *
668 * @param context The main context pointer
669 * @param str String to parse
670 * @param simple_parse Simple parse flag
671 * @return 0 and 1 for success and failure
672 */
Peer Chen8d782ee2011-01-18 21:34:18 -0500673static int
Peer Chen6f2cbc72012-03-13 11:12:39 +0800674process_statement(build_image_context *context,
675 char *str,
676 u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500677{
678 int i;
679 char *rest;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800680 parse_item *cfg_parse_item;
Peer Chen8d782ee2011-01-18 21:34:18 -0500681
Peer Chen6f2cbc72012-03-13 11:12:39 +0800682 if (simple_parse == 0)
683 cfg_parse_item = s_top_level_items;
684 else
685 cfg_parse_item = parse_simple_items;
Peer Chen8d782ee2011-01-18 21:34:18 -0500686
Peer Chen6f2cbc72012-03-13 11:12:39 +0800687 for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
688 if (!strncmp(cfg_parse_item[i].prefix, str,
689 strlen(cfg_parse_item[i].prefix))) {
690 rest = str + strlen(cfg_parse_item[i].prefix);
691
692 return cfg_parse_item[i].process(context,
693 cfg_parse_item[i].token,
Peer Chen8d782ee2011-01-18 21:34:18 -0500694 rest);
695 }
696 }
697
698 /* If this point was reached, there was a processing error. */
699 return 1;
700}
701
Peer Chen6f2cbc72012-03-13 11:12:39 +0800702/*
703 * The main function parse the config file.
704 *
705 * @param context The main context pointer
706 * @param simple_parse Simple parse flag
707 */
708void process_config_file(build_image_context *context, u_int8_t simple_parse)
Peer Chen8d782ee2011-01-18 21:34:18 -0500709{
710 char buffer[MAX_BUFFER];
711 int space = 0;
712 char current;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800713 u_int8_t c_eol_comment_start = 0; /* True after first slash */
Peer Chen8d782ee2011-01-18 21:34:18 -0500714 u_int8_t comment = 0;
715 u_int8_t string = 0;
716 u_int8_t equal_encounter = 0;
717
718 assert(context != NULL);
719 assert(context->config_file != NULL);
720
Peer Chen6f2cbc72012-03-13 11:12:39 +0800721 while ((current = fgetc(context->config_file)) != EOF) {
Peer Chen8d782ee2011-01-18 21:34:18 -0500722 if (space >= (MAX_BUFFER-1)) {
723 /* if we exceeded the max buffer size, it is likely
724 due to a missing semi-colon at the end of a line */
725 printf("Config file parsing error!");
726 exit(1);
727 }
728
729 /* Handle failure to complete "//" comment token.
730 Insert the '/' into the busffer and proceed with
731 processing the current character. */
732 if (c_eol_comment_start && current != '/') {
733 c_eol_comment_start = 0;
734 buffer[space++] = '/';
735 }
736
737 switch (current) {
738 case '\"': /* " indicates start or end of a string */
739 if (!comment) {
740 string ^= 1;
741 buffer[space++] = current;
742 }
743 break;
744 case ';':
745 if (!string && !comment) {
746 buffer[space++] = '\0';
747
Peer Chen6f2cbc72012-03-13 11:12:39 +0800748 if (process_statement(context,
749 buffer,
750 simple_parse))
751 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500752 space = 0;
753 equal_encounter = 0;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800754 } else if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500755 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500756 break;
757
758 case '/':
759 if (!string && !comment) {
760 if (c_eol_comment_start) {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800761 /* EOL comment started. */
Peer Chen8d782ee2011-01-18 21:34:18 -0500762 comment = 1;
763 c_eol_comment_start = 0;
764 } else {
765 /* Potential start of eol comment. */
766 c_eol_comment_start = 1;
767 }
Peer Chen6f2cbc72012-03-13 11:12:39 +0800768 } else if (!comment)
Peer Chen8d782ee2011-01-18 21:34:18 -0500769 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500770 break;
771
772 /* ignore whitespace. uses fallthrough */
773 case '\n':
774 case '\r': /* carriage returns end comments */
775 string = 0;
776 comment = 0;
777 c_eol_comment_start = 0;
778 case ' ':
779 case '\t':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800780 if (string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500781 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500782 break;
783
784 case '#':
Peer Chen6f2cbc72012-03-13 11:12:39 +0800785 if (!string)
Peer Chen8d782ee2011-01-18 21:34:18 -0500786 comment = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800787 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500788 buffer[space++] = current;
Peer Chen8d782ee2011-01-18 21:34:18 -0500789 break;
790
791 default:
792 if (!comment) {
793 buffer[space++] = current;
794 if (current == '=') {
Peer Chen6f2cbc72012-03-13 11:12:39 +0800795 if (!equal_encounter)
Peer Chen8d782ee2011-01-18 21:34:18 -0500796 equal_encounter = 1;
Peer Chen6f2cbc72012-03-13 11:12:39 +0800797 else
Peer Chen8d782ee2011-01-18 21:34:18 -0500798 goto error;
Peer Chen8d782ee2011-01-18 21:34:18 -0500799 }
800 }
801 break;
802 }
803 }
804
805 return;
806
807 error:
808 printf("Error parsing: %s\n", buffer);
809 exit(1);
810}