Files
OpenCellular/src/parse.c
Vince Hsu 456b8aa442 Add Tegra132 support for the cbootimage utility
This patch adds support for Tegra132. This are only slight
differences between Tegra124 and Tegra132. The command line
usage is exactly the same as other platforms like Tegra124.

The structure nvboot_mts_info is added into the bct for Tegra132.
So the bootrom and first stage bootloader know where to load the
preboot and mts images. Two parse items "Mts=" and "MtsPreboot="
are added to embedded MTS images in BCT image like what we do for
bootloader. The syntax is also the same. For example:

MtsPreboot = <preboot_image>,<load_address>,<entry_address>,Complete;
Mts        = <mts_image>,<load_address>,<entry_address>,Complete;

The load and entry addresses depned on your board design.

Four files are added in src/t132:

nvbctlib_t132.c - is cloned from nvbctlib_t124.c and adds mts
                  information getter and setter.
nvboot_bct_t132.h - adds mts structure into bct
nvboot_sdram_param_t132.h - clone of nvboot_sdram_param_t124.h
parse_t132.c - clone of parse_t124.c

Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Acked-by: Allen Martin <amartin@nvidia.com>
2014-07-15 21:42:46 -07:00

941 lines
22 KiB
C

/*
* Copyright (c) 2012-2014, 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_chipuid(char *str, u_int8_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_mts_image(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_value_chipuid(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 },
{ "MtsPreboot=", token_mts_preboot, parse_mts_image},
{ "Mts=", token_mts, parse_mts_image},
{ "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 },
{ "MtsPreboot=", token_mts_preboot, parse_mts_image},
{ "Mts=", token_mts, parse_mts_image},
{ "Version=", token_version, parse_value_u32 },
{ "OdmData=", token_odm_data, parse_value_u32 },
{ "ChipUid=", token_unique_chip_id, parse_value_chipuid },
{ "JtagCtrl=", token_secure_jtag_control, 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 transfer to chip uid.
*
* @param str String to parse
* @param chipuid Returns chip uid that was parsed
* @return the remainder of the string after the number was parsed
*/
static char *
parse_chipuid(char *str, u_int8_t *chipuid)
{
int byte_index = 0;
int paddings = 0;
char byte_str[3];
if (*str++ != '0')
return NULL;
if (*str++ != 'x')
return NULL;
paddings = strlen(str) % 2;
byte_index = strlen(str) / 2 + paddings;
if (byte_index > 16)
return NULL;
memset(chipuid, 0, 16);
while (*str != '\0' && byte_index > 0) {
char *endptr;
strncpy(byte_str, str, 2 - paddings);
byte_str[2 - paddings] = '\0';
str += 2 - paddings;
chipuid[byte_index - 1] = strtoul(byte_str, &endptr, 16);
if (*endptr)
return NULL;
byte_index--;
paddings = 0;
}
return str;
}
/*
* 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 MTS file name, load address and
* entry point information then call set_mts_image 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_mts_image(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_mts_image(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);
}
/*
* General handler for setting chip uid 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_chipuid(build_image_context *context,
parse_token token,
char *rest)
{
u_int8_t value[16];
assert(context != NULL);
assert(rest != NULL);
rest = parse_chipuid(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);
}