diff options
author | Bjorn Andersson <bjorn.andersson@linaro.org> | 2021-04-15 14:22:15 -0500 |
---|---|---|
committer | Bjorn Andersson <bjorn.andersson@linaro.org> | 2021-04-15 14:22:15 -0500 |
commit | da8dd7139a7347653a80a8d81eab511bd2afffb8 (patch) | |
tree | a6f33025c4e3892b08e34c12e3ddddb9ef29168a | |
parent | b6e0ea31d705b6e4803704356d55cf8f774a7515 (diff) |
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 <bjorn.andersson@linaro.org>
-rw-r--r-- | firehose.c | 42 | ||||
-rw-r--r-- | program.c | 142 | ||||
-rw-r--r-- | program.h | 8 | ||||
-rw-r--r-- | qdl.c | 4 |
4 files changed, 161 insertions, 35 deletions
@@ -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; @@ -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")) { - fprintf(stderr, "[PROGRAM] unrecognized tag \"%s\", ignoring\n", node->name); - continue; - } - - errors = 0; + errors = -EINVAL; - 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 (!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); - 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")) { @@ -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 @@ -415,7 +415,7 @@ static void print_usage(void) { extern const char *__progname; fprintf(stderr, - "%s [--debug] [--storage <emmc|ufs>] [--finalize-provisioning] [--include <PATH>] <prog.mbn> [<program> <patch> ...]\n", + "%s [--debug] [--storage <emmc|nand|ufs>] [--finalize-provisioning] [--include <PATH>] <prog.mbn> [<program> <patch> ...]\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; |