Add update BCT configs feature
This feature reads the BCT data from BCT or BCT with bootloader
appended binary, updates the BCT data based on config file, then
writes to new image file.
Signed-off-by: Penny Chiu <pchiu@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
diff --git a/src/cbootimage.c b/src/cbootimage.c
index 1332c5f..2fdb0f2 100644
--- a/src/cbootimage.c
+++ b/src/cbootimage.c
@@ -49,6 +49,7 @@
{"tegra", 1, NULL, 't'},
{"odmdata", 1, NULL, 'o'},
{"soc", 1, NULL, 's'},
+ {"update", 0, NULL, 'u'},
{0, 0, 0, 0},
};
@@ -63,7 +64,7 @@
static void
usage(void)
{
- printf("Usage: cbootimage [options] configfile imagename\n");
+ printf("Usage: cbootimage [options] configfile [inputimage] outputimage\n");
printf(" options:\n");
printf(" -h, --help, -? Display this message.\n");
printf(" -d, --debug Output debugging information.\n");
@@ -75,18 +76,23 @@
printf(" -s|--soc tegraNN Select target device. Must be one of:\n");
printf(" tegra20, tegra30, tegra114, tegra124.\n");
printf(" Default: tegra20.\n");
+ printf(" -u|--update Copy input image data and update bct\n");
+ printf(" configs into new image file.\n");
+ printf(" This feature is only for tegra114/124.\n");
printf(" configfile File with configuration information\n");
- printf(" imagename Output image name\n");
+ printf(" inputimage Input image name. This is required\n");
+ printf(" if -u|--update option is used.\n");
+ printf(" outputimage Output image name\n");
}
static int
process_command_line(int argc, char *argv[], build_image_context *context)
{
- int c;
+ int c, num_filenames = 2;
context->generate_bct = 0;
- while ((c = getopt_long(argc, argv, "hdg:t:o:s:", cbootcmd, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "hdg:t:o:s:u", cbootcmd, NULL)) != -1) {
switch (c) {
case 'h':
help_only = 1;
@@ -131,10 +137,14 @@
case 'o':
context->odm_data = strtoul(optarg, NULL, 16);
break;
+ case 'u':
+ context->update_image = 1;
+ num_filenames = 3;
+ break;
}
}
- if (argc - optind != 2) {
+ if (argc - optind != num_filenames) {
printf("Missing configuration and/or image file name.\n");
usage();
return -EINVAL;
@@ -145,14 +155,26 @@
t20_get_soc_config(context, &g_soc_config);
/* Open the configuration file. */
- context->config_file = fopen(argv[optind], "r");
+ context->config_file = fopen(argv[optind++], "r");
if (context->config_file == NULL) {
printf("Error opening config file.\n");
return -ENODATA;
}
+ /* Record the input image filename if update_image is necessary */
+ if (context->update_image)
+ {
+ if (context->boot_data_version != BOOTDATA_VERSION_T114 &&
+ context->boot_data_version != BOOTDATA_VERSION_T124) {
+ printf("Update image feature is only for Tegra114 and Tegra124.\n");
+ return -EINVAL;
+ }
+
+ context->input_image_filename = argv[optind++];
+ }
+
/* Record the output filename */
- context->image_filename = argv[optind + 1];
+ context->output_image_filename = argv[optind++];
return 0;
}
@@ -190,18 +212,69 @@
}
/* Open the raw output file. */
- context.raw_file = fopen(context.image_filename,
- "w+");
+ context.raw_file = fopen(context.output_image_filename, "w+");
if (context.raw_file == NULL) {
printf("Error opening raw file %s.\n",
- context.image_filename);
+ context.output_image_filename);
goto fail;
}
- /* first, if we aren't generating the bct, read in config file */
- if (context.generate_bct == 0) {
- process_config_file(&context, 1);
+ /* Read the bct data from image if bct configs needs to be updated */
+ if (context.update_image) {
+ u_int32_t offset = 0, bct_size, actual_size;
+ u_int8_t *data_block;
+ struct stat stats;
+
+ if (stat(context.input_image_filename, &stats) != 0) {
+ printf("Error: Unable to query info on input file path %s\n",
+ context.input_image_filename);
+ goto fail;
+ }
+
+ /* Get BCT_SIZE from input image file */
+ bct_size = get_bct_size_from_image(&context);
+ if (!bct_size) {
+ printf("Error: Invalid input image file %s\n",
+ context.input_image_filename);
+ goto fail;
+ }
+
+ while (stats.st_size > offset) {
+ /* Read a block of data into memory */
+ if (read_from_image(context.input_image_filename, offset, bct_size,
+ &data_block, &actual_size, file_type_bct)) {
+ printf("Error reading image file %s.\n", context.input_image_filename);
+ goto fail;
+ }
+
+ /* Check if memory data is valid BCT */
+ context.bct = data_block;
+ if (data_is_valid_bct(&context)) {
+ fseek(context.config_file, 0, SEEK_SET);
+ process_config_file(&context, 0);
+ e = sign_bct(&context, context.bct);
+ if (e != 0) {
+ printf("Signing BCT failed, error: %d.\n", e);
+ goto fail;
+ }
+ }
+
+ /* Write the block of data to file */
+ if (actual_size != write_data_block(context.raw_file, offset, actual_size, data_block)) {
+ printf("Error writing image file %s.\n", context.output_image_filename);
+ goto fail;
+ }
+
+ offset += bct_size;
+ }
+
+ printf("Image file %s has been successfully generated!\n",
+ context.output_image_filename);
+ goto fail;
}
+ /* If we aren't generating the bct, read in config file */
+ else if (context.generate_bct == 0)
+ process_config_file(&context, 1);
/* Generate the new bct file */
else {
/* Initialize the bct memory */
@@ -218,7 +291,7 @@
fwrite(context.bct, 1, context.bct_size,
context.raw_file);
printf("New BCT file %s has been successfully generated!\n",
- context.image_filename);
+ context.output_image_filename);
goto fail;
}
@@ -234,7 +307,7 @@
printf("Error writing image file.\n");
else
printf("Image file %s has been successfully generated!\n",
- context.image_filename);
+ context.output_image_filename);
fail:
/* Close the file(s). */
diff --git a/src/cbootimage.h b/src/cbootimage.h
index ed3b2f9..6def766 100644
--- a/src/cbootimage.h
+++ b/src/cbootimage.h
@@ -45,6 +45,8 @@
#define BOOTDATA_VERSION_T114 NVBOOT_BOOTDATA_VERSION(0x35, 0x1)
#define BOOTDATA_VERSION_T124 NVBOOT_BOOTDATA_VERSION(0x40, 0x1)
+#define NVBOOT_CONFIG_TABLE_SIZE_MAX 8192
+
/*
* Enumerations
*/
@@ -61,7 +63,8 @@
typedef struct build_image_context_rec
{
FILE *config_file;
- char *image_filename;
+ char *output_image_filename;
+ char *input_image_filename;
FILE *raw_file;
u_int32_t block_size;
u_int32_t block_size_log2;
@@ -99,6 +102,7 @@
u_int32_t odm_data; /* The odm data value */
u_int8_t unique_chip_id[16]; /* The unique chip uid */
u_int8_t secure_jtag_control; /* The flag for enabling jtag control */
+ u_int8_t update_image; /* The flag for updating image */
} build_image_context;
/* Function prototypes */
diff --git a/src/data_layout.c b/src/data_layout.c
index 0a64ec2..c848a61 100644
--- a/src/data_layout.c
+++ b/src/data_layout.c
@@ -451,6 +451,8 @@
/* Read the BL into memory. */
if (read_from_image(context->newbl_filename,
+ 0,
+ MAX_BOOTLOADER_SIZE,
&bl_storage,
&bl_actual_size,
bl_filetype) == 1) {
@@ -670,12 +672,15 @@
int err = 0;
if (read_from_image(context->bct_filename,
- &bct_storage,
- &bct_actual_size,
- bct_filetype) == 1) {
+ 0,
+ NVBOOT_CONFIG_TABLE_SIZE_MAX,
+ &bct_storage,
+ &bct_actual_size,
+ bct_filetype) == 1) {
printf("Error reading bct file %s.\n", context->bct_filename);
exit(1);
}
+
context->bct_size = bct_actual_size;
if (context->bct_init != 1)
err = init_bct(context);
@@ -686,18 +691,12 @@
memcpy(context->bct, bct_storage, context->bct_size);
free(bct_storage);
- /* get proper soc_config pointer by polling each supported chip */
- if (if_bct_is_t20_get_soc_config(context, &g_soc_config))
- return 0;
- if (if_bct_is_t30_get_soc_config(context, &g_soc_config))
- return 0;
- if (if_bct_is_t114_get_soc_config(context, &g_soc_config))
- return 0;
- if (if_bct_is_t124_get_soc_config(context, &g_soc_config))
- return 0;
+ if (!data_is_valid_bct(context))
+ return ENODATA;
- return ENODATA;
+ return err;
}
+
/*
* Update the next_bct_blk and make it point to the next
* new blank block according to bct_copy given.
@@ -898,3 +897,50 @@
free(empty_blk);
return 0;
}
+
+int write_data_block(FILE *fp, u_int32_t offset, u_int32_t size, u_int8_t *buffer)
+{
+ if (fseek(fp, offset, 0))
+ return -1;
+
+ return fwrite(buffer, 1, size, fp);
+}
+
+int data_is_valid_bct(build_image_context *context)
+{
+ /* get proper soc_config pointer by polling each supported chip */
+ if (if_bct_is_t20_get_soc_config(context, &g_soc_config))
+ return 1;
+ if (if_bct_is_t30_get_soc_config(context, &g_soc_config))
+ return 1;
+ if (if_bct_is_t114_get_soc_config(context, &g_soc_config))
+ return 1;
+ if (if_bct_is_t124_get_soc_config(context, &g_soc_config))
+ return 1;
+
+ return 0;
+}
+
+int get_bct_size_from_image(build_image_context *context)
+{
+ u_int8_t buffer[NVBOOT_CONFIG_TABLE_SIZE_MAX];
+ u_int32_t bct_size = 0;
+ FILE *fp;
+
+ fp = fopen(context->input_image_filename, "r");
+ if (!fp)
+ return ENODATA;
+
+ if (!fread(buffer, 1, NVBOOT_CONFIG_TABLE_SIZE_MAX, fp)) {
+ fclose(fp);
+ return ENODATA;
+ }
+
+ context->bct = buffer;
+ if (data_is_valid_bct(context) && g_soc_config->get_bct_size)
+ bct_size = g_soc_config->get_bct_size();
+
+ fclose(fp);
+ context->bct = 0;
+ return bct_size;
+}
diff --git a/src/data_layout.h b/src/data_layout.h
index 9ee8267..12da165 100644
--- a/src/data_layout.h
+++ b/src/data_layout.h
@@ -50,6 +50,15 @@
write_block_raw(struct build_image_context_rec *context);
int
+write_data_block(FILE *fp, u_int32_t offset, u_int32_t size, u_int8_t *buffer);
+
+int
+data_is_valid_bct(build_image_context *context);
+
+int
+get_bct_size_from_image(build_image_context *context);
+
+int
begin_update(build_image_context *context);
#endif /* #ifndef INCLUDED_DATA_LAYOUT_H */
diff --git a/src/parse.h b/src/parse.h
index 114168c..64d0a65 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -753,6 +753,13 @@
u_int8_t *bct);
/*
+ * Get the BCT structure size
+ *
+ * @return BCT size
+ */
+ int (*get_bct_size)();
+
+ /*
* Check if the token is supported to dump
*
* @param id The parse token value
diff --git a/src/set.c b/src/set.c
index 0419505..130c451 100644
--- a/src/set.c
+++ b/src/set.c
@@ -43,6 +43,8 @@
int
read_from_image(char *filename,
+ u_int32_t offset,
+ u_int32_t max_size,
u_int8_t **image,
u_int32_t *actual_size,
file_type f_type)
@@ -57,6 +59,8 @@
return result;
}
+ fseek(fp, offset, SEEK_SET);
+
if (stat(filename, &stats) != 0) {
printf("Error: Unable to query info on bootloader path %s\n",
filename);
@@ -64,14 +68,21 @@
goto cleanup;
}
- *actual_size = (u_int32_t)stats.st_size;
-
- if (f_type == file_type_bl && *actual_size > MAX_BOOTLOADER_SIZE) {
- printf("Error: Bootloader file %s is too large.\n",
- filename);
- result = 1;
- goto cleanup;
+ if (f_type == file_type_bl) {
+ if ((stats.st_size - offset) > max_size) {
+ printf("Error: Bootloader file %s is too large.\n",
+ filename);
+ result = 1;
+ goto cleanup;
+ }
+ *actual_size = (u_int32_t)stats.st_size;
+ } else {
+ if ((stats.st_size - offset) < max_size)
+ *actual_size = stats.st_size - offset;
+ else
+ *actual_size = max_size;
}
+
*image = malloc(*actual_size);
if (*image == NULL) {
result = 1;
@@ -80,7 +91,8 @@
memset(*image, 0, *actual_size);
- if (fread(*image, 1, (size_t)stats.st_size, fp) != stats.st_size) {
+ if (fread(*image, 1, (size_t)(*actual_size), fp) !=
+ (size_t)(*actual_size)) {
result = 1;
goto cleanup;
}
diff --git a/src/set.h b/src/set.h
index 754ed7a..97ecc76 100644
--- a/src/set.h
+++ b/src/set.h
@@ -42,6 +42,8 @@
int
read_from_image(char *filename,
+ u_int32_t offset,
+ u_int32_t max_size,
u_int8_t **Image,
u_int32_t *actual_size,
file_type f_type);
diff --git a/src/t114/nvbctlib_t114.c b/src/t114/nvbctlib_t114.c
index 5b1f28b..dad8f4f 100644
--- a/src/t114/nvbctlib_t114.c
+++ b/src/t114/nvbctlib_t114.c
@@ -1064,6 +1064,11 @@
return 0;
}
+int t114_get_bct_size()
+{
+ return sizeof(nvboot_config_table);
+}
+
int t114_bct_token_supported(parse_token token)
{
int index;
@@ -1108,6 +1113,7 @@
.set_value = t114_bct_set_value,
.get_value = t114_bct_get_value,
.set_data = t114_bct_set_data,
+ .get_bct_size = t114_get_bct_size,
.token_supported = t114_bct_token_supported,
.devtype_table = s_devtype_table_t114,
diff --git a/src/t124/nvbctlib_t124.c b/src/t124/nvbctlib_t124.c
index 5f2c440..5df93cd 100644
--- a/src/t124/nvbctlib_t124.c
+++ b/src/t124/nvbctlib_t124.c
@@ -1077,6 +1077,11 @@
return 0;
}
+int t124_get_bct_size()
+{
+ return sizeof(nvboot_config_table);
+}
+
int t124_bct_token_supported(parse_token token)
{
int index;
@@ -1121,6 +1126,7 @@
.set_value = t124_bct_set_value,
.get_value = t124_bct_get_value,
.set_data = t124_bct_set_data,
+ .get_bct_size = t124_get_bct_size,
.token_supported = t124_bct_token_supported,
.devtype_table = s_devtype_table_t124,
diff --git a/src/t20/nvbctlib_t20.c b/src/t20/nvbctlib_t20.c
index 30a95a3..4e07bf2 100644
--- a/src/t20/nvbctlib_t20.c
+++ b/src/t20/nvbctlib_t20.c
@@ -645,6 +645,11 @@
return 0;
}
+int t20_get_bct_size()
+{
+ return sizeof(nvboot_config_table);
+}
+
int t20_bct_token_supported(parse_token token)
{
int index;
@@ -689,6 +694,7 @@
.set_value = t20_bct_set_value,
.get_value = t20_bct_get_value,
.set_data = t20_bct_set_data,
+ .get_bct_size = t20_get_bct_size,
.token_supported = t20_bct_token_supported,
.devtype_table = s_devtype_table_t20,
diff --git a/src/t30/nvbctlib_t30.c b/src/t30/nvbctlib_t30.c
index 1e9697b..df3bef0 100644
--- a/src/t30/nvbctlib_t30.c
+++ b/src/t30/nvbctlib_t30.c
@@ -852,6 +852,11 @@
return 0;
}
+int t30_get_bct_size()
+{
+ return sizeof(nvboot_config_table);
+}
+
int t30_bct_token_supported(parse_token token)
{
int index;
@@ -896,6 +901,7 @@
.set_value = t30_bct_set_value,
.get_value = t30_bct_get_value,
.set_data = t30_bct_set_data,
+ .get_bct_size = t30_get_bct_size,
.token_supported = t30_bct_token_supported,
.devtype_table = s_devtype_table_t30,