summaryrefslogtreecommitdiffstats
path: root/scripts/tegra/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/tegra/parse.c')
-rw-r--r--scripts/tegra/parse.c803
1 files changed, 803 insertions, 0 deletions
diff --git a/scripts/tegra/parse.c b/scripts/tegra/parse.c
new file mode 100644
index 0000000000..464ee8ff40
--- /dev/null
+++ b/scripts/tegra/parse.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ */
+
+/*
+ * parse.c - Parsing support for the cbootimage tool
+ */
+
+#include <ctype.h>
+#include "parse.h"
+#include "cbootimage.h"
+#include "data_layout.h"
+#include "crypto.h"
+#include "set.h"
+
+/*
+ * Function prototypes
+ *
+ * ParseXXX() parses XXX in the input
+ * SetXXX() sets state based on the parsing results but does not perform
+ * any parsing of its own
+ * A ParseXXX() function may call other parse functions and set functions.
+ * A SetXXX() function may not call any parseing functions.
+ */
+
+static int
+set_array(build_image_context *context,
+ u_int32_t index,
+ parse_token token,
+ u_int32_t value);
+static char *parse_u32(char *str, u_int32_t *val);
+static char *parse_u8(char *str, u_int32_t *val);
+static char *parse_filename(char *str, char *name, int chars_remaining);
+static char *parse_enum(build_image_context *context,
+ char *str,
+ enum_item *table,
+ u_int32_t *val);
+static char
+*parse_field_name(char *rest, field_item *field_table, field_item **field);
+static char
+*parse_field_value(build_image_context *context,
+ char *rest,
+ field_item *field,
+ u_int32_t *value);
+static int
+parse_array(build_image_context *context, parse_token token, char *rest);
+static int
+parse_bootloader(build_image_context *context, parse_token token, char *rest);
+static int
+parse_value_u32(build_image_context *context, parse_token token, char *rest);
+static int
+parse_bct_file(build_image_context *context, parse_token token, char *rest);
+static char
+*parse_end_state(char *str, char *uname, int chars_remaining);
+static int
+parse_dev_param(build_image_context *context, parse_token token, char *rest);
+static int
+parse_sdram_param(build_image_context *context, parse_token token, char *rest);
+
+static int process_statement(build_image_context *context,
+ char *str,
+ u_int8_t simple_parse);
+
+static parse_item parse_simple_items[] =
+{
+ { "Bctfile=", token_bct_file, parse_bct_file },
+ { "BootLoader=", token_bootloader, parse_bootloader },
+ { "Redundancy=", token_redundancy, parse_value_u32 },
+ { "Bctcopy=", token_bct_copy, parse_value_u32 },
+ { "Version=", token_version, parse_value_u32 },
+ { "PreBctPadBlocks=", token_pre_bct_pad_blocks, parse_value_u32 },
+ { NULL, 0, NULL } /* Must be last */
+};
+
+static parse_item s_top_level_items[] = {
+ { "Bctfile=", token_bct_file, parse_bct_file },
+ { "Attribute=", token_attribute, parse_value_u32 },
+ { "Attribute[", token_attribute, parse_array },
+ { "PageSize=", token_page_size, parse_value_u32 },
+ { "BlockSize=", token_block_size, parse_value_u32 },
+ { "PartitionSize=", token_partition_size, parse_value_u32 },
+ { "DevType[", token_dev_type, parse_array },
+ { "DeviceParam[", token_dev_param, parse_dev_param },
+ { "SDRAM[", token_sdram, parse_sdram_param },
+ { "BootLoader=", token_bootloader, parse_bootloader },
+ { "Redundancy=", token_redundancy, parse_value_u32 },
+ { "Bctcopy=", token_bct_copy, parse_value_u32 },
+ { "Version=", token_version, parse_value_u32 },
+ { "OdmData=", token_odm_data, parse_value_u32 },
+ { NULL, 0, NULL } /* Must be last */
+};
+
+/* Macro to simplify parser code a bit. */
+#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
+
+/*
+ * Parse the given string and find the u32 dec/hex number.
+ *
+ * @param str String to parse
+ * @param val Returns value that was parsed
+ * @return the remainder of the string after the number was parsed
+ */
+static char *
+parse_u32(char *str, u_int32_t *val)
+{
+ u_int32_t value = 0;
+ u_int32_t digit;
+
+ while (*str == '0')
+ str++;
+
+ if (tolower(*str) == 'x') {
+ str++;
+ while (isxdigit(*str)) {
+ value *= 16;
+ digit = tolower(*str);
+ value += digit <= '9' ? digit - '0' : digit - 'a' + 10;
+ str++;
+ }
+ } else {
+ while (*str >= '0' && *str <= '9') {
+ value = value*10 + (*str - '0');
+ str++;
+ }
+ }
+ *val = value;
+ return str;
+}
+
+/*
+ * Parse the given string and find the u8 dec/hex number.
+ *
+ * @param str String to parse
+ * @param val Returns value that was parsed
+ * @return the remainder of the string after the number was parsed
+ */
+static char *
+parse_u8(char *str, u_int32_t *val)
+{
+ char *retval;
+
+ retval = parse_u32(str, val);
+
+ if (*val > 0xff) {
+ printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
+ printf(" Parsed value = %d. Remaining text = %s\n",
+ *val, retval);
+ }
+
+ return retval;
+}
+
+
+/*
+ * Parse the given string and find the file name then
+ * return the rest of the string.
+ *
+ * @param str String to parse
+ * @param name Returns the filename that was parsed
+ * @param chars_remaining The maximum length of filename
+ * @return the remainder of the string after the name was parsed
+ */
+static char *
+parse_filename(char *str, char *name, int chars_remaining)
+{
+ /*
+ * Check if the filename buffer is out of space, preserving one
+ * character to null terminate the string.
+ */
+ while (isalnum(*str) || strchr("\\/~_-+:.", *str)) {
+
+ chars_remaining--;
+
+ if (chars_remaining < 1)
+ return NULL;
+ *name++ = *str++;
+ }
+
+ /* Null terminate the filename. */
+ *name = '\0';
+
+ return str;
+}
+
+/*
+ * Parse the given string and find the match field name listed
+ * in field table.
+ *
+ * @param rest String to parse
+ * @param field_table The field table to parse
+ * @param field Returns the field item that was parsed
+ * @return NULL or the remainder of the string after the field item was parsed
+ */
+static char
+*parse_field_name(char *rest, field_item *field_table, field_item **field)
+{
+ u_int32_t i;
+ u_int32_t field_name_len = 0;
+
+ assert(field_table != NULL);
+ assert(rest != NULL);
+ assert(field != NULL);
+
+ while (rest[field_name_len] != '=')
+ field_name_len++;
+
+ /* Parse the field name. */
+ for (i = 0; field_table[i].name != NULL; i++) {
+ if ((strlen(field_table[i].name) == field_name_len) &&
+ !strncmp(field_table[i].name,
+ rest,
+ field_name_len)) {
+
+ *field = &(field_table[i]);
+ rest = rest + field_name_len;
+ return rest;
+ }
+ }
+
+ /* Field wasn't found or a parse error occurred. */
+ return NULL;
+}
+
+/*
+ * Parse the value based on the field table
+ *
+ * @param context The main context pointer
+ * @param rest String to parse
+ * @param field Field item to parse
+ * @param value Returns the value that was parsed
+ * @return the remainder of the string after the value was parsed
+ */
+static char
+*parse_field_value(build_image_context *context,
+ char *rest,
+ field_item *field,
+ u_int32_t *value)
+{
+ assert(rest != NULL);
+ assert(field != NULL);
+ assert((field->type != field_type_enum)
+ || (field->enum_table != NULL));
+
+ switch (field->type) {
+ case field_type_enum:
+ rest = parse_enum(context, rest, field->enum_table, value);
+ break;
+
+ case field_type_u32:
+ rest = parse_u32(rest, value);
+ break;
+
+ case field_type_u8:
+ rest = parse_u8(rest, value);
+ break;
+
+ default:
+ printf("Unexpected field type %d at line %d\n",
+ field->type, __LINE__);
+ rest = NULL;
+ break;
+ }
+
+ return rest;
+}
+
+/*
+ * Parse the given string and find the match enum item listed
+ * in table.
+ *
+ * @param context The main context pointer
+ * @param str String to parse
+ * @param table Enum item table to parse
+ * @param value Returns the value that was parsed
+ * @return the remainder of the string after the item was parsed
+ */
+static char *
+parse_enum(build_image_context *context,
+ char *str,
+ enum_item *table,
+ u_int32_t *val)
+{
+ int i;
+ char *rest;
+
+ for (i = 0; table[i].name != NULL; i++) {
+ if (!strncmp(table[i].name, str,
+ strlen(table[i].name))) {
+ *val = table[i].value;
+ rest = str + strlen(table[i].name);
+ return rest;
+ }
+ }
+ return parse_u32(str, val);
+
+}
+
+/*
+ * Parse the given string and find the bootloader file name, load address and
+ * entry point information then call set_bootloader function.
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int parse_bootloader(build_image_context *context,
+ parse_token token,
+ char *rest)
+{
+ char filename[MAX_BUFFER];
+ char e_state[MAX_STR_LEN];
+ u_int32_t load_addr;
+ u_int32_t entry_point;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ if (context->generate_bct != 0)
+ return 0;
+ /* Parse the file name. */
+ rest = parse_filename(rest, filename, MAX_BUFFER);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the load address. */
+ rest = parse_u32(rest, &load_addr);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the entry point. */
+ rest = parse_u32(rest, &entry_point);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the end state. */
+ rest = parse_end_state(rest, e_state, MAX_STR_LEN);
+ if (rest == NULL)
+ return 1;
+ if (strncmp(e_state, "Complete", strlen("Complete")))
+ return 1;
+
+ /* Parsing has finished - set the bootloader */
+ return set_bootloader(context, filename, load_addr, entry_point);
+}
+
+/*
+ * Parse the given string and find the array items in config file.
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int
+parse_array(build_image_context *context, parse_token token, char *rest)
+{
+ u_int32_t index;
+ u_int32_t value;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the index. */
+ rest = parse_u32(rest, &index);
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the closing bracket. */
+ if (*rest != ']')
+ return 1;
+ rest++;
+
+ /* Parse the equals sign.*/
+ if (*rest != '=')
+ return 1;
+ rest++;
+
+ /* Parse the value based on the field table. */
+ switch (token) {
+ case token_attribute:
+ rest = parse_u32(rest, &value);
+ break;
+ case token_dev_type:
+ rest = parse_enum(context,
+ rest,
+ g_soc_config->devtype_table,
+ &value);
+ break;
+
+ default:
+ /* Unknown token */
+ return 1;
+ }
+
+ if (rest == NULL)
+ return 1;
+
+ /* Store the result. */
+ return set_array(context, index, token, value);
+}
+
+/*
+ * Call hw interface to set the value for array item in bct such as device
+ * type and bootloader attribute.
+ *
+ * @param context The main context pointer
+ * @param index The index for array
+ * @param token The parse token value
+ * @param value The value to set
+ * @return 0 and -ENODATA for success and failure
+ */
+
+static int
+set_array(build_image_context *context,
+ u_int32_t index,
+ parse_token token,
+ u_int32_t value)
+{
+ int err = 0;
+
+ assert(context != NULL);
+
+ switch (token) {
+ case token_attribute:
+ err = g_soc_config->setbl_param(index,
+ token_bl_attribute,
+ &value,
+ context->bct);
+ break;
+ case token_dev_type:
+ err = g_soc_config->set_dev_param(context,
+ index,
+ token_dev_type,
+ value);
+ break;
+ default:
+ break;
+ }
+ return err;
+}
+
+/*
+ * General handler for setting u_int32_t values in config files.
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int parse_value_u32(build_image_context *context,
+ parse_token token,
+ char *rest)
+{
+ u_int32_t value;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ rest = parse_u32(rest, &value);
+ if (rest == NULL)
+ return 1;
+
+ return context_set_value(context, token, value);
+}
+
+/*
+ * Parse the given string and find the bct file name.
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int
+parse_bct_file(build_image_context *context, parse_token token, char *rest)
+{
+ char filename[MAX_BUFFER];
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the file name. */
+ rest = parse_filename(rest, filename, MAX_BUFFER);
+ if (rest == NULL)
+ return 1;
+
+ /* Parsing has finished - set the bctfile */
+ context->bct_filename = filename;
+ /* Read the bct file to buffer */
+ if (read_bct_file(context))
+ return 1;
+
+ update_context(context);
+ return 0;
+}
+
+static char *
+parse_end_state(char *str, char *uname, int chars_remaining)
+{
+ while (isalpha(*str)) {
+
+ *uname++ = *str++;
+ if (--chars_remaining < 0)
+ return NULL;
+ }
+ *uname = '\0';
+ return str;
+}
+
+/*
+ * Parse the given string and find device parameter listed in device table
+ * and value for this device parameter. If match, call the corresponding
+ * function in the table to set device parameter.
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int
+parse_dev_param(build_image_context *context, parse_token token, char *rest)
+{
+ u_int32_t i;
+ u_int32_t value;
+ field_item *field;
+ u_int32_t index;
+ parse_subfield_item *device_item = NULL;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the index. */
+ rest = parse_u32(rest, &index);
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the closing bracket. */
+ if (*rest != ']')
+ return 1;
+ rest++;
+
+ /* Parse the following '.' */
+ if (*rest != '.')
+ return 1;
+ rest++;
+
+ /* Parse the device name. */
+ for (i = 0; g_soc_config->device_type_table[i].prefix != NULL; i++) {
+ if (!strncmp(g_soc_config->device_type_table[i].prefix,
+ rest, strlen(g_soc_config->device_type_table[i].prefix))) {
+
+ device_item = &(g_soc_config->device_type_table[i]);
+ rest = rest + strlen(g_soc_config->device_type_table[i].prefix);
+
+ /* Parse the field name. */
+ rest = parse_field_name(rest,
+ g_soc_config->device_type_table[i].field_table,
+ &field);
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the equals sign.*/
+ if (*rest != '=')
+ return 1;
+ rest++;
+
+ /* Parse the value based on the field table. */
+ rest = parse_field_value(context, rest, field, &value);
+ if (rest == NULL)
+ return 1;
+ return device_item->process(context,
+ index, field->token, value);
+ }
+ }
+ return 1;
+}
+
+/*
+ * Parse the given string and find sdram parameter and value in config
+ * file. If match, call the corresponding function set the sdram parameter.
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int
+parse_sdram_param(build_image_context *context, parse_token token, char *rest)
+{
+ u_int32_t value;
+ field_item *field;
+ u_int32_t index;
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the index. */
+ rest = parse_u32(rest, &index);
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the closing bracket. */
+ if (*rest != ']')
+ return 1;
+ rest++;
+
+ /* Parse the following '.' */
+ if (*rest != '.')
+ return 1;
+ rest++;
+
+ /* Parse the field name. */
+ rest = parse_field_name(rest, g_soc_config->sdram_field_table, &field);
+
+ if (rest == NULL)
+ return 1;
+
+ /* Parse the equals sign.*/
+ if (*rest != '=')
+ return 1;
+ rest++;
+
+ /* Parse the value based on the field table. */
+ rest = parse_field_value(context, rest, field, &value);
+ if (rest == NULL)
+ return 1;
+
+ /* Store the result. */
+ return g_soc_config->set_sdram_param(context,
+ index,
+ field->token,
+ value);
+}
+
+/*
+ * Compare the given string with item listed in table.
+ * Execute the proper process function if match.
+ *
+ * @param context The main context pointer
+ * @param str String to parse
+ * @param simple_parse Simple parse flag
+ * @return 0 and 1 for success and failure
+ */
+static int
+process_statement(build_image_context *context,
+ char *str,
+ u_int8_t simple_parse)
+{
+ int i;
+ char *rest;
+ parse_item *cfg_parse_item;
+
+ if (simple_parse == 0)
+ cfg_parse_item = s_top_level_items;
+ else
+ cfg_parse_item = parse_simple_items;
+
+ for (i = 0; cfg_parse_item[i].prefix != NULL; i++) {
+ if (!strncmp(cfg_parse_item[i].prefix, str,
+ strlen(cfg_parse_item[i].prefix))) {
+ rest = str + strlen(cfg_parse_item[i].prefix);
+
+ return cfg_parse_item[i].process(context,
+ cfg_parse_item[i].token,
+ rest);
+ }
+ }
+
+ /* If this point was reached, there was a processing error. */
+ return 1;
+}
+
+/*
+ * The main function parse the config file.
+ *
+ * @param context The main context pointer
+ * @param simple_parse Simple parse flag
+ */
+void process_config_file(build_image_context *context, u_int8_t simple_parse)
+{
+ char buffer[MAX_BUFFER];
+ int space = 0;
+ int current;
+ u_int8_t c_eol_comment_start = 0; /* True after first slash */
+ u_int8_t comment = 0;
+ u_int8_t string = 0;
+ u_int8_t equal_encounter = 0;
+
+ assert(context != NULL);
+ assert(context->config_file != NULL);
+
+ while ((current = fgetc(context->config_file)) != EOF) {
+ if (space >= (MAX_BUFFER-1)) {
+ /* if we exceeded the max buffer size, it is likely
+ due to a missing semi-colon at the end of a line */
+ printf("Config file parsing error!");
+ exit(1);
+ }
+
+ /* Handle failure to complete "//" comment token.
+ Insert the '/' into the busffer and proceed with
+ processing the current character. */
+ if (c_eol_comment_start && current != '/') {
+ c_eol_comment_start = 0;
+ buffer[space++] = '/';
+ }
+
+ switch (current) {
+ case '\"': /* " indicates start or end of a string */
+ if (!comment) {
+ string ^= 1;
+ buffer[space++] = current;
+ }
+ break;
+ case ';':
+ if (!string && !comment) {
+ buffer[space++] = '\0';
+
+ if (process_statement(context,
+ buffer,
+ simple_parse))
+ goto error;
+ space = 0;
+ equal_encounter = 0;
+ } else if (string)
+ buffer[space++] = current;
+ break;
+
+ case '/':
+ if (!string && !comment) {
+ if (c_eol_comment_start) {
+ /* EOL comment started. */
+ comment = 1;
+ c_eol_comment_start = 0;
+ } else {
+ /* Potential start of eol comment. */
+ c_eol_comment_start = 1;
+ }
+ } else if (!comment)
+ buffer[space++] = current;
+ break;
+
+ /* ignore whitespace. uses fallthrough */
+ case '\n':
+ case '\r': /* carriage returns end comments */
+ string = 0;
+ comment = 0;
+ c_eol_comment_start = 0;
+ case ' ':
+ case '\t':
+ if (string)
+ buffer[space++] = current;
+ break;
+
+ case '#':
+ if (!string)
+ comment = 1;
+ else
+ buffer[space++] = current;
+ break;
+
+ default:
+ if (!comment) {
+ buffer[space++] = current;
+ if (current == '=') {
+ if (!equal_encounter)
+ equal_encounter = 1;
+ else
+ goto error;
+ }
+ }
+ break;
+ }
+ }
+
+ return;
+
+ error:
+ printf("Error parsing: %s\n", buffer);
+ exit(1);
+}