diff options
-rw-r--r-- | GNUmakefile | 2 | ||||
-rw-r--r-- | cbootimage.c | 20 | ||||
-rw-r--r-- | cbootimage.h | 1 | ||||
-rw-r--r-- | nvbctlib.h | 102 | ||||
-rw-r--r-- | nvbctlib_ap20.c | 89 | ||||
-rw-r--r-- | nvboot_bct.h | 142 | ||||
-rw-r--r-- | parse.c | 299 | ||||
-rw-r--r-- | parse.h | 76 | ||||
-rw-r--r-- | set.c | 118 | ||||
-rw-r--r-- | set.h | 12 |
10 files changed, 797 insertions, 64 deletions
diff --git a/GNUmakefile b/GNUmakefile index f5b1e51..9a2fbf1 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -12,7 +12,7 @@ OBJS := $(patsubst %.c,%.o,$(notdir $(C_FILES))) TARGET = cbootimage CC = gcc -CFLAGS=-Wall -O +CFLAGS=-Wall -O -lm $(TARGET):$(OBJS) $(CC) -o $(TARGET) $(OBJS) $(CFLAGS) diff --git a/cbootimage.c b/cbootimage.c index 1792749..1df6238 100644 --- a/cbootimage.c +++ b/cbootimage.c @@ -59,6 +59,7 @@ usage(void) printf(" options:\n"); printf(" -h, --help, -? Display this message.\n"); printf(" -d, --debug Output debugging information.\n"); + printf(" -gbct Generate the new bct file.\n"); printf(" configfile File with configuration information\n"); printf(" imagename Output image name\n"); } @@ -68,6 +69,8 @@ process_command_line(int argc, char *argv[], build_image_context *context) { int arg = 1; + context->generate_bct = 0; + while (arg < argc) { /* Process the next argument. */ if (!strcmp(argv[arg], "-h") || @@ -80,6 +83,9 @@ process_command_line(int argc, char *argv[], build_image_context *context) !strcmp(argv[arg], "--debug")) { enable_debug = 1; arg++; + } else if (!strcmp(argv[arg], "-gbct")) { + context->generate_bct = 1; + arg++; } else if (argv[arg][0] == '-') { printf("Illegal option %s\n", argv[arg]); usage(); @@ -168,6 +174,20 @@ main(int argc, char *argv[]) /* Parse & process the contents of the config file. */ process_config_file(&context); + /* Generate the new bct file */ + if (context.generate_bct != 0) { + /* Signing the bct. */ + e = sign_bct(&context, context.bct); + if (e != 0) + printf("Signing BCT failed, error: %d.\n", e); + + fwrite(context.bct, 1, sizeof(nvboot_config_table), + context.raw_file); + printf("New BCT file %s has been successfully generated!\n", + context.image_filename); + goto fail; + } + /* Update the bct file */ /* Update the add on file */ e = update_addon_item(&context); diff --git a/cbootimage.h b/cbootimage.h index 41c9baf..173e76a 100644 --- a/cbootimage.h +++ b/cbootimage.h @@ -111,6 +111,7 @@ typedef struct build_image_context_rec u_int32_t newbl_load_addr; u_int32_t newbl_entry_point; u_int32_t newbl_attr; + u_int8_t generate_bct; u_int8_t *bct; struct addon_table_rec addon_tbl; @@ -42,40 +42,66 @@ * constants. */ typedef enum { - nvbct_lib_id_none = 0, - - nvbct_lib_id_crypto_hash, - nvbct_lib_id_random_aes_blk, - nvbct_lib_id_boot_data_version, - nvbct_lib_id_block_size_log2, - nvbct_lib_id_page_size_log2, - nvbct_lib_id_partition_size, - nvbct_lib_id_bootloader_used, - nvbct_lib_id_bootloaders_max, - nvbct_lib_id_reserved, - nvbct_lib_id_reserved_size, - nvbct_lib_id_reserved_offset, - nvbct_lib_id_bct_size, - nvbct_lib_id_hash_size, - nvbct_lib_id_crypto_offset, - nvbct_lib_id_crypto_length, - nvbct_lib_id_max_bct_search_blks, - - nvbct_lib_id_bl_version, - nvbct_lib_id_bl_start_blk, - nvbct_lib_id_bl_start_page, - nvbct_lib_id_bl_length, - nvbct_lib_id_bl_load_addr, - nvbct_lib_id_bl_entry_point, - nvbct_lib_id_bl_attribute, - nvbct_lib_id_bl_crypto_hash, - - nvbct_lib_id_max, - - nvbct_lib_id_force32 = 0x7fffffff + nvbct_lib_id_none = 0, + + nvbct_lib_id_crypto_hash, + nvbct_lib_id_random_aes_blk, + nvbct_lib_id_boot_data_version, + nvbct_lib_id_block_size_log2, + nvbct_lib_id_page_size_log2, + nvbct_lib_id_partition_size, + nvbct_lib_id_dev_type, + nvbct_lib_id_bootloader_used, + nvbct_lib_id_bootloaders_max, + nvbct_lib_id_reserved, + nvbct_lib_id_reserved_size, + nvbct_lib_id_reserved_offset, + nvbct_lib_id_bct_size, + nvbct_lib_id_hash_size, + nvbct_lib_id_crypto_offset, + nvbct_lib_id_crypto_length, + nvbct_lib_id_max_bct_search_blks, + nvbct_lib_id_num_param_sets, + nvbct_lib_id_dev_type_sdmmc, + nvbct_lib_id_dev_type_spi, + + nvbct_lib_id_sdmmc_clock_divider, + nvbct_lib_id_sdmmc_data_width, + nvbct_lib_id_sdmmc_max_power_class_supported, + nvbct_lib_id_spiflash_read_command_type_fast, + nvbct_lib_id_spiflash_clock_source, + nvbct_lib_id_spiflash_clock_divider, + nvbct_lib_id_sdmmc_data_width_4bit, + nvbct_lib_id_sdmmc_data_width_8bit, + nvbct_lib_id_spi_clock_source_pllp_out0, + nvbct_lib_id_spi_clock_source_pllc_out0, + nvbct_lib_id_spi_clock_source_pllm_out0, + nvbct_lib_id_spi_clock_source_clockm, + + nvbct_lib_id_bl_version, + nvbct_lib_id_bl_start_blk, + nvbct_lib_id_bl_start_page, + nvbct_lib_id_bl_length, + nvbct_lib_id_bl_load_addr, + nvbct_lib_id_bl_entry_point, + nvbct_lib_id_bl_attribute, + nvbct_lib_id_bl_crypto_hash, + + nvbct_lib_id_max, + + nvbct_lib_id_force32 = 0x7fffffff } nvbct_lib_id; +typedef int (*nvbct_lib_get_dev_param)(u_int32_t set, + nvbct_lib_id id, + u_int32_t *data, + u_int8_t *bct); +typedef int (*nvbct_lib_set_dev_param)(u_int32_t set, + nvbct_lib_id id, + u_int32_t data, + u_int8_t *bct); + typedef int (*nvbct_lib_get_bl_param)(u_int32_t set, nvbct_lib_id id, u_int32_t *data, @@ -110,15 +136,17 @@ typedef int (*nvbct_lib_set_data)(nvbct_lib_id id, */ typedef struct nvbct_lib_fns_rec { - nvbct_lib_get_value get_value; - nvbct_lib_set_value set_value; + nvbct_lib_get_value get_value; + nvbct_lib_set_value set_value; - nvbct_lib_get_data get_data; - nvbct_lib_set_data set_data; + nvbct_lib_get_data get_data; + nvbct_lib_set_data set_data; - nvbct_lib_get_bl_param getbl_param; - nvbct_lib_set_bl_param setbl_param; + nvbct_lib_get_bl_param getbl_param; + nvbct_lib_set_bl_param setbl_param; + nvbct_lib_get_dev_param getdev_param; + nvbct_lib_set_dev_param setdev_param; } nvbct_lib_fns; void nvbct_lib_get_fns(nvbct_lib_fns *fns); diff --git a/nvbctlib_ap20.c b/nvbctlib_ap20.c index 2535432..2f803b5 100644 --- a/nvbctlib_ap20.c +++ b/nvbctlib_ap20.c @@ -28,6 +28,16 @@ /* nvbctlib_ap20.c: The implementation of the nvbctlib API for AP20. */ /* Definitions that simplify the code which follows. */ +#define CASE_GET_DEV_PARAM(dev, x) \ +case nvbct_lib_id_##dev##_##x:\ + *data = bct_ptr->dev_params[set].dev##_params.x; \ + break + +#define CASE_SET_DEV_PARAM(dev, x) \ +case nvbct_lib_id_##dev##_##x:\ + bct_ptr->dev_params[set].dev##_params.x = data; \ + break + #define CASE_GET_BL_PARAM(x) \ case nvbct_lib_id_bl_##x:\ *data = bct_ptr->bootloader[set].x; \ @@ -51,7 +61,7 @@ case nvbct_lib_id_##id:\ #define CASE_GET_CONST_PREFIX(id, val_prefix) \ case nvbct_lib_id_##id:\ - *data = val_prefix##id; \ + *data = val_prefix##_##id; \ break #define CASE_SET_NVU32(id) \ @@ -72,6 +82,68 @@ case nvbct_lib_id_##id:\ memcpy(&(bct_ptr->id), data, size); \ break +static int +getdev_param(u_int32_t set, + nvbct_lib_id id, + u_int32_t *data, + u_int8_t *bct) +{ + nvboot_config_table *bct_ptr = (nvboot_config_table*)bct; + + if (data == NULL || bct == NULL) + return -ENODATA; + + switch (id) { + CASE_GET_DEV_PARAM(sdmmc, clock_divider); + CASE_GET_DEV_PARAM(sdmmc, data_width); + CASE_GET_DEV_PARAM(sdmmc, max_power_class_supported); + + CASE_GET_DEV_PARAM(spiflash, clock_source); + CASE_GET_DEV_PARAM(spiflash, clock_divider); + CASE_GET_DEV_PARAM(spiflash, read_command_type_fast); + + case nvbct_lib_id_dev_type: + *data = bct_ptr->dev_type[set]; + break; + + default: + return -ENODATA; + } + + return 0; +} + +static int +setdev_param(u_int32_t set, + nvbct_lib_id id, + u_int32_t data, + u_int8_t *bct) +{ + nvboot_config_table *bct_ptr = (nvboot_config_table*)bct; + + if (bct == NULL) + return -ENODATA; + + switch (id) { + CASE_SET_DEV_PARAM(sdmmc, clock_divider); + CASE_SET_DEV_PARAM(sdmmc, data_width); + CASE_SET_DEV_PARAM(sdmmc, max_power_class_supported); + + CASE_SET_DEV_PARAM(spiflash, clock_source); + CASE_SET_DEV_PARAM(spiflash, clock_divider); + CASE_SET_DEV_PARAM(spiflash, read_command_type_fast); + + case nvbct_lib_id_dev_type: + bct_ptr->dev_type[set] = data; + break; + + default: + return -ENODATA; + } + + return 0; + +} static int getbl_param(u_int32_t set, @@ -166,6 +238,7 @@ bct_get_value(nvbct_lib_id id, u_int32_t *data, u_int8_t *bct) CASE_GET_NVU32(block_size_log2); CASE_GET_NVU32(page_size_log2); CASE_GET_NVU32(partition_size); + CASE_GET_NVU32(num_param_sets); CASE_GET_NVU32(bootloader_used); /* @@ -199,6 +272,15 @@ bct_get_value(nvbct_lib_id id, u_int32_t *data, u_int8_t *bct) CASE_GET_CONST(max_bct_search_blks, NVBOOT_MAX_BCT_SEARCH_BLOCKS); + CASE_GET_CONST_PREFIX(dev_type_sdmmc, nvboot); + CASE_GET_CONST_PREFIX(dev_type_spi, nvboot); + CASE_GET_CONST_PREFIX(sdmmc_data_width_4bit, nvboot); + CASE_GET_CONST_PREFIX(sdmmc_data_width_8bit, nvboot); + CASE_GET_CONST_PREFIX(spi_clock_source_pllp_out0, nvboot); + CASE_GET_CONST_PREFIX(spi_clock_source_pllc_out0, nvboot); + CASE_GET_CONST_PREFIX(spi_clock_source_pllm_out0, nvboot); + CASE_GET_CONST_PREFIX(spi_clock_source_clockm, nvboot); + default: return -ENODATA; } @@ -221,6 +303,7 @@ bct_set_value(nvbct_lib_id id, u_int32_t data, u_int8_t *bct) CASE_SET_NVU32(block_size_log2); CASE_SET_NVU32(page_size_log2); CASE_SET_NVU32(partition_size); + CASE_SET_NVU32(num_param_sets); CASE_SET_NVU32(bootloader_used); default: @@ -279,4 +362,8 @@ nvbct_lib_get_fns(nvbct_lib_fns *fns) fns->getbl_param = getbl_param; fns->setbl_param = setbl_param; + + fns->getdev_param = getdev_param; + fns->setdev_param = setdev_param; + } diff --git a/nvboot_bct.h b/nvboot_bct.h index 734ed3b..75ffb42 100644 --- a/nvboot_bct.h +++ b/nvboot_bct.h @@ -46,7 +46,13 @@ */ #define NVBOOT_MAX_BOOTLOADERS 4 -#define NVBOOT_BCT_USED_DATA_SIZE 534 +#define NVBOOT_BCT_USED_DATA_SIZE 2052 + +/** + * Defines the maximum number of device parameter sets in the BCT. + * The value must be equal to (1 << # of device straps) + */ +#define NVBOOT_BCT_MAX_PARAM_SETS 4 /** * Defines the number of entries (bits) in the bad block table. @@ -93,6 +99,135 @@ typedef struct nvboot_hash_rec u_int32_t hash[NVBOOT_CMAC_AES_HASH_LENGTH]; } nvboot_hash; +/// Defines various data widths supported. +typedef enum +{ + /** + * Specifies a 1 bit interface to eMMC. + * Note that 1-bit data width is only for the driver's internal use. + * Fuses doesn't provide option to select 1-bit data width. + * The driver selects 1-bit internally based on need. + * It is used for reading Extended CSD and when the power class + * requirements of a card for 4-bit or 8-bit transfers are not + * supported by the target board. + */ + nvboot_sdmmc_data_width_1bit = 0, + + /// Specifies a 4 bit interface to eMMC. + nvboot_sdmmc_data_width_4bit = 1, + + /// Specifies a 8 bit interface to eMMC. + nvboot_sdmmc_data_width_8bit = 2, + + nvboot_sdmmc_data_width_num, + nvboot_sdmmc_data_width_force32 = 0x7FFFFFFF +} nvboot_sdmmc_data_width; + +/// Defines the parameters that can be changed after BCT is read. +typedef struct nvboot_sdmmc_params_rec +{ + /** + * Specifies the clock divider for the SDMMC controller's clock source, + * which is PLLP running at 432MHz. If it is set to 18, then the SDMMC + * controller runs at 432/18 = 24MHz. + */ + u_int8_t clock_divider; + + /// Specifies the data bus width. Supported data widths are 4/8 bits. + nvboot_sdmmc_data_width data_width; + + /** + * Max Power class supported by the target board. + * The driver determines the best data width and clock frequency + * supported within the power class range (0 to Max) if the selected + * data width cannot be used at the chosen clock frequency. + */ + u_int8_t max_power_class_supported; + u_int32_t reserved; +} nvboot_sdmmc_params; + +typedef enum +{ + /// Specifies SPI clock source to be PLLP. + nvboot_spi_clock_source_pllp_out0 = 0, + + /// Specifies SPI clock source to be PLLC. + nvboot_spi_clock_source_pllc_out0, + + /// Specifies SPI clock source to be PLLM. + nvboot_spi_clock_source_pllm_out0, + + /// Specifies SPI clock source to be ClockM. + nvboot_spi_clock_source_clockm, + + nvboot_spi_clock_source_num, + nvboot_spi_clock_source_force32 = 0x7FFFFFF +} nvboot_spi_clock_source; + + +/** + * Defines the parameters SPI FLASH devices. + */ +typedef struct nvboot_spiflash_params_rec +{ + /** + * Specifies the clock source to use. + */ + nvboot_spi_clock_source clock_source; + + /** + * Specifes the clock divider to use. + * The value is a 7-bit value based on an input clock of 432Mhz. + * Divider = (432+ DesiredFrequency-1)/DesiredFrequency; + * Typical values: + * NORMAL_READ at 20MHz: 22 + * FAST_READ at 33MHz: 14 + * FAST_READ at 40MHz: 11 + * FAST_READ at 50MHz: 9 + */ + u_int8_t clock_divider; + + /** + * Specifies the type of command for read operations. + * NV_FALSE specifies a NORMAL_READ Command + * NV_TRUE specifies a FAST_READ Command + */ + u_int8_t read_command_type_fast; +} nvboot_spiflash_params; + +/** +* Defines the union of the parameters required by each device. +*/ +typedef union{ + /// Specifies optimized parameters for eMMC and eSD + nvboot_sdmmc_params sdmmc_params; + /// Specifies optimized parameters for SPI NOR + nvboot_spiflash_params spiflash_params; +} nvboot_dev_params; + +/** + * Identifies the types of devices from which the system booted. + * Used to identify primary and secondary boot devices. + * @note These no longer match the fuse API device values (for + * backward compatibility with AP15). + */ +typedef enum +{ + /// Specifies a default (unset) value. + nvboot_dev_type_none = 0, + + /// Specifies SPI NOR. + nvboot_dev_type_spi = 3, + + /// Specifies SDMMC (either eMMC or eSD). + nvboot_dev_type_sdmmc, + + nvboot_dev_type_max, + + /// Ignore -- Forces compilers to make 32-bit enums. + nvboot_dev_type_force32 = 0x7FFFFFFF + } nvboot_dev_type; + /** * Stores information needed to locate and verify a boot loader. * @@ -138,7 +273,10 @@ typedef struct nvboot_config_table_rec u_int32_t block_size_log2; u_int32_t page_size_log2; u_int32_t partition_size; - u_int32_t bct_used_data[NVBOOT_BCT_USED_DATA_SIZE]; + u_int32_t num_param_sets; + nvboot_dev_type dev_type[NVBOOT_BCT_MAX_PARAM_SETS]; + nvboot_dev_params dev_params[NVBOOT_BCT_MAX_PARAM_SETS]; + u_int8_t bct_used_data[NVBOOT_BCT_USED_DATA_SIZE]; nvboot_badblock_table badblock_table; u_int32_t bootloader_used; nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS]; @@ -52,7 +52,19 @@ */ static char *parse_u32(char *statement, u_int32_t *val); +static char *parse_u8(char *statement, u_int32_t *val); static char *parse_filename(char *statement, char *name, int chars_remaining); +static char *parse_enum(build_image_context *context, + char *statement, + 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 @@ -66,13 +78,111 @@ parse_addon(build_image_context *context, parse_token token, char *rest); static char *parse_string(char *statement, char *uname, int chars_remaining); static char *parse_end_state(char *statement, char *uname, int chars_remaining); +static int +parse_dev_param(build_image_context *context, parse_token token, char *rest); + static int process_statement(build_image_context *context, char *statement); +static enum_item s_devtype_table[] = +{ + { "NvBootDevType_Sdmmc", nvbct_lib_id_dev_type_sdmmc }, + { "NvBootDevType_Spi", nvbct_lib_id_dev_type_spi }, + { "Sdmmc", nvbct_lib_id_dev_type_sdmmc }, + { "Spi", nvbct_lib_id_dev_type_spi }, + + { NULL, 0 } +}; + +static enum_item s_sdmmc_data_width_table[] = +{ + { + "NvBootSdmmcDataWidth_4Bit", + nvbct_lib_id_sdmmc_data_width_4bit + }, + { + "NvBootSdmmcDataWidth_8Bit", + nvbct_lib_id_sdmmc_data_width_8bit + }, + { "4Bit", nvbct_lib_id_sdmmc_data_width_4bit }, + { "8Bit", nvbct_lib_id_sdmmc_data_width_8bit }, + { NULL, 0 } +}; + +static enum_item s_spi_clock_source_table[] = +{ + { + "NvBootSpiClockSource_PllPOut0", + nvbct_lib_id_spi_clock_source_pllp_out0 + }, + { + "NvBootSpiClockSource_PllCOut0", + nvbct_lib_id_spi_clock_source_pllc_out0 + }, + { + "NvBootSpiClockSource_PllMOut0", + nvbct_lib_id_spi_clock_source_pllm_out0 + }, + { + "NvBootSpiClockSource_ClockM", + nvbct_lib_id_spi_clock_source_clockm + }, + + { "ClockSource_PllPOut0", nvbct_lib_id_spi_clock_source_pllp_out0 }, + { "ClockSource_PllCOut0", nvbct_lib_id_spi_clock_source_pllc_out0 }, + { "ClockSource_PllMOut0", nvbct_lib_id_spi_clock_source_pllm_out0 }, + { "ClockSource_ClockM", nvbct_lib_id_spi_clock_source_clockm }, + + + { "PllPOut0", nvbct_lib_id_spi_clock_source_pllp_out0 }, + { "PllCOut0", nvbct_lib_id_spi_clock_source_pllc_out0 }, + { "PllMOut0", nvbct_lib_id_spi_clock_source_pllm_out0 }, + { "ClockM", nvbct_lib_id_spi_clock_source_clockm }, + + { NULL, 0 } +}; + +static field_item s_sdmmc_table[] = +{ + { "ClockDivider", token_clock_divider, field_type_u32, NULL }, + { "DataWidth", token_data_width, + field_type_enum, s_sdmmc_data_width_table }, + { "MaxPowerClassSupported", token_max_power_class_supported, + field_type_u32, NULL }, + + { NULL, 0, 0, NULL } +}; + +static field_item s_spiflash_table[] = +{ + { "ReadCommandTypeFast", token_read_command_type_fast, + field_type_u8, NULL }, + { "ClockDivider", token_clock_divider, field_type_u8, NULL }, + { "ClockSource", token_clock_source, + field_type_enum, s_spi_clock_source_table }, + + { NULL, 0, 0, NULL } +}; + +static parse_subfield_item s_device_type_table[] = +{ + { "SdmmcParams.", token_sdmmc_params, + s_sdmmc_table, set_sdmmc_param }, + { "SpiFlashParams.", token_spiflash_params, + s_spiflash_table, set_spiflash_param }, + + { NULL, 0, NULL } +}; + 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 }, { "BootLoader=", token_bootloader, parse_bootloader }, { "Redundancy=", token_redundancy, parse_value_u32 }, { "Version=", token_version, parse_value_u32 }, @@ -120,6 +230,23 @@ parse_u32(char *statement, u_int32_t *val) return statement; } +char * +parse_u8(char *statement, u_int32_t *val) +{ + char *retval; + + retval = parse_u32(statement, 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; +} + + /* This parsing code was initially borrowed from nvcamera_config_parse.c. */ /* Returns the address of the character after the parsed data. */ static char * @@ -152,6 +279,100 @@ parse_filename(char *statement, char *name, int chars_remaining) return statement; } +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; +} + +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; +} + +static char * +parse_enum(build_image_context *context, + char *statement, + enum_item *table, + u_int32_t *val) +{ + int i; + char *rest; + int e; + + for (i = 0; table[i].name != NULL; i++) { + if (!strncmp(table[i].name, statement, + strlen(table[i].name))) { + /* Lookup the correct value for the token. */ + e = context->bctlib.get_value(table[i].value, + val, context->bct); + if (e) { + printf("Error looking up token %d.\n", table[i].value); + printf("\"%s\" is not valid for this chip.\n", + table[i].name); + *val = -1; + } + + rest = statement + strlen(table[i].name); + return rest; + } + } + return parse_u32(statement, val); + +} /* * parse_bootloader(): Processes commands to set a bootloader. */ @@ -167,6 +388,8 @@ static int parse_bootloader(build_image_context *context, 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) @@ -228,13 +451,16 @@ parse_array(build_image_context *context, parse_token token, char *rest) /* Parse the value based on the field table. */ switch(token) { - case token_attribute: - rest = parse_u32(rest, &value); - break; - - default: - /* Unknown token */ - return 1; + case token_attribute: + rest = parse_u32(rest, &value); + break; + case token_dev_type: + rest = parse_enum(context, rest, s_devtype_table, &value); + break; + + default: + /* Unknown token */ + return 1; } if (rest == NULL) @@ -394,6 +620,65 @@ parse_addon(build_image_context *context, parse_token token, char *rest) return 0; } +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; s_device_type_table[i].prefix != NULL; i++) { + if (!strncmp(s_device_type_table[i].prefix, + rest, strlen(s_device_type_table[i].prefix))) { + + device_item = &(s_device_type_table[i]); + rest = rest + strlen(s_device_type_table[i].prefix); + + /* Parse the field name. */ + rest = parse_field_name(rest, + s_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; + +} /* Return 0 on success, 1 on error */ static int process_statement(build_image_context *context, char *statement) @@ -41,28 +41,76 @@ typedef enum { - token_none = 0, - token_attribute, - token_bootloader, - token_page_size, - token_redundancy, - token_version, - token_bct_file, - token_addon, - - token_force32 = 0x7fffffff + token_none = 0, + token_attribute, + token_bootloader, + token_block_size, + token_page_size, + token_partition_size, + token_dev_type, + token_dev_param, + token_redundancy, + token_version, + token_bct_file, + token_addon, + token_sdmmc_params, + token_spiflash_params, + token_data_width, + token_clock_divider, + token_clock_source, + token_read_command_type_fast, + token_max_power_class_supported, + + token_force32 = 0x7fffffff } parse_token; +typedef enum +{ + field_type_none = 0, + field_type_enum, + field_type_u32, + field_type_u8, + field_type_force32 = 0x7fffffff +} field_type; + /* Forward declarations */ typedef int (*process_function)(build_image_context *context, parse_token token, - char *Remiainder); + char *remainder); + +typedef int (*process_subfield_function)(build_image_context *context, + u_int32_t index, + parse_token token, + u_int32_t value); + + +typedef struct +{ + char *name; + u_int32_t value; +} enum_item; + +typedef struct +{ + char *name; + u_int32_t token; + field_type type; + enum_item *enum_table; +} field_item; + +typedef struct +{ + char *prefix; + parse_token token; + field_item *field_table; + process_subfield_function process; +} parse_subfield_item; typedef struct { - char *prefix; - parse_token token; - process_function process; + char *prefix; + parse_token token; + process_function process; } parse_item; /* @@ -24,6 +24,7 @@ * set.c - State setting support for the cbootimage tool */ +#include <math.h> #include "set.h" #include "cbootimage.h" #include "crypto.h" @@ -39,6 +40,22 @@ * A SetXXX() function may not call any parseing functions. */ +#define NV_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define CASE_DEVICE_VALUE(prefix, id) \ + case token_##id: \ + (void)context->bctlib.setdev_param(index, \ + nvbct_lib_id_##prefix##_##id, \ + value, \ + context->bct); \ + break + +#define DEFAULT() \ + default: \ + printf("Unexpected token %d at line %d\n", \ + token, __LINE__); \ + return 1 + int read_from_image(char *filename, u_int32_t page_size, @@ -59,7 +76,7 @@ read_from_image(char *filename, if (stat(filename, &stats) != 0) { printf("Error: Unable to query info on bootloader path %s\n", - filename); + filename); result = 1; goto cleanup; } @@ -147,7 +164,14 @@ context_set_array(build_image_context *context, context->bct); break; - DEFAULT(); + case token_dev_type: + (void)context->bctlib.setdev_param(index, + nvbct_lib_id_dev_type, + value, + context->bct); + break; + + DEFAULT(); } return 0; } @@ -166,8 +190,41 @@ int context_set_value(build_image_context *context, context->newbl_attr = value; break; + case token_block_size: + context->block_size = value; + context->block_size_log2 = log2(value); + + if (context->memory != NULL) { + printf("Error: Too late to change block size.\n"); + return 1; + } + + if (value != (u_int32_t)(1 << context->block_size_log2)) { + printf("Error: Block size must be a power of 2.\n"); + return 1; + } + context->pages_per_blk= 1 << (context->block_size_log2- + context->page_size_log2); + SET_VALUE(block_size_log2, context->block_size_log2); + break; + + case token_partition_size: + if (context->memory != NULL) { + printf("Error: Too late to change block size.\n"); + return 1; + } + + context->partition_size= value; + SET_VALUE(partition_size, value); + break; + case token_page_size: context->page_size = value; + context->page_size_log2 = log2(value); + context->pages_per_blk= 1 << (context->block_size_log2- + context->page_size_log2); + + SET_VALUE(page_size_log2, context->page_size_log2); break; case token_redundancy: context->redundancy = value; @@ -304,3 +361,60 @@ set_other_field(build_image_context *context, } +static void +update_num_param_sets(build_image_context *context, u_int32_t index) +{ + u_int32_t num_params; + + GET_VALUE(num_param_sets, &num_params); + num_params = NV_MAX(num_params, index + 1); + SET_VALUE(num_param_sets, num_params); +} + +/* + * set_sdmmc_param(): Processes commands to set MoviNand parameters. + */ +int +set_sdmmc_param(build_image_context *context, + u_int32_t index, + parse_token token, + u_int32_t value) +{ + assert(context != NULL); + assert(context->bct != NULL); + + update_num_param_sets(context, index); + + switch (token) { + CASE_DEVICE_VALUE(sdmmc, clock_divider); + CASE_DEVICE_VALUE(sdmmc, data_width); + CASE_DEVICE_VALUE(sdmmc, max_power_class_supported); + DEFAULT(); + } + + return 0; +} + +/* + * set_spiflash_param(): Processes commands to set SpiFlash parameters. + */ +int +set_spiflash_param(build_image_context *context, + u_int32_t index, + parse_token token, + u_int32_t value) +{ + assert(context != NULL); + assert(context->bct != NULL); + + update_num_param_sets(context, index); + + switch (token) { + CASE_DEVICE_VALUE(spiflash, clock_divider); + CASE_DEVICE_VALUE(spiflash, clock_source); + CASE_DEVICE_VALUE(spiflash, read_command_type_fast); + DEFAULT(); + } + + return 0; +} @@ -71,6 +71,18 @@ set_other_field(build_image_context *context, int index); int +set_sdmmc_param(build_image_context *context, + u_int32_t index, + parse_token token, + u_int32_t value); + +int +set_spiflash_param(build_image_context *context, + u_int32_t index, + parse_token token, + u_int32_t value); + +int read_from_image(char *filename, u_int32_t page_size, u_int8_t **Image, |