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@xxxxxxxxxx> --- src/cbootimage.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++--------- src/cbootimage.h | 10 +++++- src/data_layout.c | 86 +++++++++++++++++++++++++++++++++++++++++++--------- src/data_layout.h | 9 ++++++ src/set.c | 28 ++++++++++++----- src/set.h | 2 ++ 6 files changed, 188 insertions(+), 38 deletions(-) diff --git a/src/cbootimage.c b/src/cbootimage.c index 1332c5f..7477414 100644 --- a/src/cbootimage.c +++ b/src/cbootimage.c @@ -49,6 +49,7 @@ struct option cbootcmd[] = { {"tegra", 1, NULL, 't'}, {"odmdata", 1, NULL, 'o'}, {"soc", 1, NULL, 's'}, + {"update", 0, NULL, 'u'}, {0, 0, 0, 0}, }; @@ -63,7 +64,7 @@ write_image_file(build_image_context *context) 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,22 @@ usage(void) 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(" 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 +136,14 @@ process_command_line(int argc, char *argv[], build_image_context *context) 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 +154,18 @@ process_command_line(int argc, char *argv[], build_image_context *context) 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) + 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 +203,66 @@ main(int argc, char *argv[]) } /* 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 */ + write_data_block(context.raw_file, offset, actual_size, data_block); + + 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 +279,7 @@ main(int argc, char *argv[]) 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 +295,7 @@ main(int argc, char *argv[]) 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 252c41e..121bc95 100644 --- a/src/cbootimage.h +++ b/src/cbootimage.h @@ -44,6 +44,12 @@ #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 +#define NVBOOT_CONFIG_TABLE_SIZE_T20 4080 +#define NVBOOT_CONFIG_TABLE_SIZE_T30 6128 +#define NVBOOT_CONFIG_TABLE_SIZE_T114 8192 +#define NVBOOT_CONFIG_TABLE_SIZE_T124 8192 + /* * Enumerations */ @@ -60,7 +66,8 @@ typedef enum 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; @@ -98,6 +105,7 @@ typedef struct build_image_context_rec 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..a7a89fc 100644 --- a/src/data_layout.c +++ b/src/data_layout.c @@ -451,6 +451,8 @@ write_bootloaders(build_image_context *context) /* Read the BL into memory. */ if (read_from_image(context->newbl_filename, + 0, + MAX_BOOTLOADER_SIZE, &bl_storage, &bl_actual_size, bl_filetype) == 1) { @@ -665,17 +667,20 @@ int read_bct_file(struct build_image_context_rec *context) { u_int8_t *bct_storage; /* Holds the Bl after reading */ - u_int32_t bct_actual_size; /* In bytes */ + u_int32_t bct_actual_size; /* In bytes */ file_type bct_filetype = file_type_bct; 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 @@ read_bct_file(struct build_image_context_rec *context) 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,62 @@ write_block_raw(build_image_context *context) 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; + + fwrite(buffer, 1, size, fp); + return 0; +} + +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)) { + context->bct = buffer; + if (data_is_valid_bct(context)) { + switch (context->boot_data_version) { + case BOOTDATA_VERSION_T20: + bct_size = NVBOOT_CONFIG_TABLE_SIZE_T20; + break; + case BOOTDATA_VERSION_T30: + bct_size = NVBOOT_CONFIG_TABLE_SIZE_T30; + break; + case BOOTDATA_VERSION_T114: + bct_size = NVBOOT_CONFIG_TABLE_SIZE_T114; + break; + case BOOTDATA_VERSION_T124: + bct_size = NVBOOT_CONFIG_TABLE_SIZE_T124; + break; + } + } + } + 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 @@ int 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/set.c b/src/set.c index 4a78b71..46dcfdc 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 @@ read_from_image(char *filename, 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 @@ read_from_image(char *filename, 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 @@ read_from_image(char *filename, 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 @@ context_set_value(build_image_context *context, 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); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html