aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2021-04-15 14:22:15 -0500
committerBjorn Andersson <bjorn.andersson@linaro.org>2021-04-15 14:22:15 -0500
commitda8dd7139a7347653a80a8d81eab511bd2afffb8 (patch)
treea6f33025c4e3892b08e34c12e3ddddb9ef29168a
parentb6e0ea31d705b6e4803704356d55cf8f774a7515 (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.c42
-rw-r--r--program.c142
-rw-r--r--program.h8
-rw-r--r--qdl.c4
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")) {
- 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")) {
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 <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;