From da8dd7139a7347653a80a8d81eab511bd2afffb8 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 15 Apr 2021 14:22:15 -0500 Subject: [PATCH] program: Introduce erase tag support NAND based devices comes with a few minor tweaks to the program tag and an additional erase tag, split the program code and add the handling of the erase tag. Signed-off-by: Bjorn Andersson --- firehose.c | 42 ++++++++++++++++ program.c | 142 +++++++++++++++++++++++++++++++++++++++++------------ program.h | 8 ++- qdl.c | 4 +- 4 files changed, 161 insertions(+), 35 deletions(-) diff --git a/firehose.c b/firehose.c index ff8ec80..1912b53 100644 --- a/firehose.c +++ b/firehose.c @@ -294,6 +294,39 @@ static int firehose_configure(struct qdl_device *qdl, bool skip_storage_init, co #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +static int firehose_erase(struct qdl_device *qdl, struct program *program) +{ + xmlNode *root; + xmlNode *node; + xmlDoc *doc; + int ret; + + doc = xmlNewDoc((xmlChar*)"1.0"); + root = xmlNewNode(NULL, (xmlChar*)"data"); + xmlDocSetRootElement(doc, root); + + node = xmlNewChild(root, NULL, (xmlChar*)"erase", NULL); + xml_setpropf(node, "PAGES_PER_BLOCK", "%d", program->pages_per_block); + xml_setpropf(node, "SECTOR_SIZE_IN_BYTES", "%d", program->sector_size); + xml_setpropf(node, "num_partition_sectors", "%d", program->num_sectors); + xml_setpropf(node, "start_sector", "%d", program->start_sector); + + ret = firehose_write(qdl, doc); + if (ret < 0) { + fprintf(stderr, "[PROGRAM] failed to write program command\n"); + goto out; + } + + ret = firehose_read(qdl, 30, firehose_nop_parser); + fprintf(stderr, "[ERASE] erase 0x%x+0x%x %s\n", + program->start_sector, program->num_sectors, + ret ? "failed" : "succeeded"); + +out: + xmlFreeDoc(doc); + return ret; +} + static int firehose_program(struct qdl_device *qdl, struct program *program, int fd) { unsigned num_sectors; @@ -340,6 +373,11 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int if (program->filename) xml_setpropf(node, "filename", "%s", program->filename); + if (program->is_nand) { + xml_setpropf(node, "PAGES_PER_BLOCK", "%d", program->pages_per_block); + xml_setpropf(node, "last_sector", "%d", program->last_sector); + } + ret = firehose_write(qdl, doc); if (ret < 0) { fprintf(stderr, "[PROGRAM] failed to write program command\n"); @@ -600,6 +638,10 @@ int firehose_run(struct qdl_device *qdl, const char *incdir, const char *storage if (ret) return ret; + ret = erase_execute(qdl, firehose_erase); + if (ret) + return ret; + ret = program_execute(qdl, firehose_program, incdir); if (ret) return ret; diff --git a/program.c b/program.c index 4c8abfb..c817015 100644 --- a/program.c +++ b/program.c @@ -37,13 +37,90 @@ #include "program.h" #include "qdl.h" - + static struct program *programes; static struct program *programes_last; -int program_load(const char *program_file) +static int load_erase_tag(xmlNode *node, bool is_nand) { struct program *program; + int errors = 0; + + if (!is_nand) { + fprintf(stderr, "got \"erase\" tag for non-NAND storage\n"); + return -EINVAL; + } + + program = calloc(1, sizeof(struct program)); + + + program->is_nand = true; + program->is_erase = true; + + program->pages_per_block = attr_as_unsigned(node, "PAGES_PER_BLOCK", &errors); + program->sector_size = attr_as_unsigned(node, "SECTOR_SIZE_IN_BYTES", &errors); + program->num_sectors = attr_as_unsigned(node, "num_partition_sectors", &errors); + program->start_sector = attr_as_unsigned(node, "start_sector", &errors); + + if (errors) { + fprintf(stderr, "[PROGRAM] errors while parsing erase tag\n"); + free(program); + return -EINVAL; + } + + if (programes) { + programes_last->next = program; + programes_last = program; + } else { + programes = program; + programes_last = program; + } + + return 0; +} + +static int load_program_tag(xmlNode *node, bool is_nand) +{ + struct program *program; + int errors = 0; + + program = calloc(1, sizeof(struct program)); + + program->is_nand = is_nand; + + program->sector_size = attr_as_unsigned(node, "SECTOR_SIZE_IN_BYTES", &errors); + program->filename = attr_as_string(node, "filename", &errors); + program->label = attr_as_string(node, "label", &errors); + program->num_sectors = attr_as_unsigned(node, "num_partition_sectors", &errors); + program->partition = attr_as_unsigned(node, "physical_partition_number", &errors); + program->start_sector = attr_as_unsigned(node, "start_sector", &errors); + + if (is_nand) { + program->pages_per_block = attr_as_unsigned(node, "PAGES_PER_BLOCK", &errors); + program->last_sector = attr_as_unsigned(node, "last_sector", &errors); + } else { + program->file_offset = attr_as_unsigned(node, "file_sector_offset", &errors); + } + + if (errors) { + fprintf(stderr, "[PROGRAM] errors while parsing program\n"); + free(program); + return -EINVAL; + } + + if (programes) { + programes_last->next = program; + programes_last = program; + } else { + programes = program; + programes_last = program; + } + + return 0; +} + +int program_load(const char *program_file, bool is_nand) +{ xmlNode *node; xmlNode *root; xmlDoc *doc; @@ -60,43 +137,24 @@ int program_load(const char *program_file) if (node->type != XML_ELEMENT_NODE) continue; - if (xmlStrcmp(node->name, (xmlChar*)"program")) { + errors = -EINVAL; + + if (!xmlStrcmp(node->name, (xmlChar *)"erase")) + errors = load_erase_tag(node, is_nand); + else if (!xmlStrcmp(node->name, (xmlChar *)"program")) + errors = load_program_tag(node, is_nand); + else fprintf(stderr, "[PROGRAM] unrecognized tag \"%s\", ignoring\n", node->name); - continue; - } - errors = 0; - - program = calloc(1, sizeof(struct program)); - - program->sector_size = attr_as_unsigned(node, "SECTOR_SIZE_IN_BYTES", &errors); - program->file_offset = attr_as_unsigned(node, "file_sector_offset", &errors); - program->filename = attr_as_string(node, "filename", &errors); - program->label = attr_as_string(node, "label", &errors); - program->num_sectors = attr_as_unsigned(node, "num_partition_sectors", &errors); - program->partition = attr_as_unsigned(node, "physical_partition_number", &errors); - program->start_sector = attr_as_unsigned(node, "start_sector", &errors); - - if (errors) { - fprintf(stderr, "[PROGRAM] errors while parsing program\n"); - free(program); - continue; - } - - if (programes) { - programes_last->next = program; - programes_last = program; - } else { - programes = program; - programes_last = program; - } + if (errors) + return errors; } xmlFreeDoc(doc); return 0; } - + int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd), const char *incdir) { @@ -107,7 +165,7 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, int fd; for (program = programes; program; program = program->next) { - if (!program->filename) + if (program->is_erase || !program->filename) continue; filename = program->filename; @@ -134,6 +192,24 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, return 0; } +int erase_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program)) +{ + struct program *program; + int ret; + + + for (program = programes; program; program = program->next) { + if (!program->is_erase) + continue; + + ret = apply(qdl, program); + if (ret) + return ret; + } + + return 0; +} + /** * program_find_bootable_partition() - find one bootable partition * @@ -151,6 +227,8 @@ int program_find_bootable_partition(void) for (program = programes; program; program = program->next) { label = program->label; + if (!label) + continue; if (!strcmp(label, "xbl") || !strcmp(label, "xbl_a") || !strcmp(label, "sbl1")) { diff --git a/program.h b/program.h index 3d51a8f..4fe0167 100644 --- a/program.h +++ b/program.h @@ -5,6 +5,7 @@ #include "qdl.h" struct program { + unsigned pages_per_block; unsigned sector_size; unsigned file_offset; const char *filename; @@ -12,13 +13,18 @@ struct program { unsigned num_sectors; unsigned partition; unsigned start_sector; + unsigned last_sector; + + bool is_nand; + bool is_erase; struct program *next; }; -int program_load(const char *program_file); +int program_load(const char *program_file, bool is_nand); int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd), const char *incdir); +int erase_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program)); int program_find_bootable_partition(void); #endif diff --git a/qdl.c b/qdl.c index 14685bc..ec7d520 100644 --- a/qdl.c +++ b/qdl.c @@ -415,7 +415,7 @@ static void print_usage(void) { extern const char *__progname; fprintf(stderr, - "%s [--debug] [--storage ] [--finalize-provisioning] [--include ] [ ...]\n", + "%s [--debug] [--storage ] [--finalize-provisioning] [--include ] [ ...]\n", __progname); } @@ -478,7 +478,7 @@ int main(int argc, char **argv) errx(1, "patch_load %s failed", argv[optind]); break; case QDL_FILE_PROGRAM: - ret = program_load(argv[optind]); + ret = program_load(argv[optind], !strcmp(storage, "nand")); if (ret < 0) errx(1, "program_load %s failed", argv[optind]); break;