mirror of
https://github.com/linux-msm/qdl.git
synced 2026-02-25 13:12:25 -08:00
sparse: Parse sparse files at load time
The nested loop and the parsing of the sparse files during application isn't very clean, and results in parse errors coming late in the process. It also results in two different lists of program elements, and the sparse entries are currently not cleaned up after application. Instead update the program parser, such that when a sparse entry is found the sparse image is parsed and the chunks are added to the program list. The filename member of the original program entry is dropped, to prevent programming the region, while still tracking it. This could allow us to later implement an "erase before flash" of the program segments. This results in a much cleaner application of the program entries, and any errors are detected up front. Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
This commit is contained in:
committed by
Bjorn Andersson
parent
3eb702d950
commit
6a67b6bd64
125
program.c
125
program.c
@@ -58,11 +58,9 @@ static int load_erase_tag(xmlNode *node, bool is_nand)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct program *program_load_sparse(struct program *program, int fd)
|
||||
static int program_load_sparse(struct program *program, int fd)
|
||||
{
|
||||
struct program *program_sparse = NULL;
|
||||
struct program *programes_sparse = NULL;
|
||||
struct program *programes_sparse_last = NULL;
|
||||
char tmp[PATH_MAX];
|
||||
|
||||
sparse_header_t sparse_header;
|
||||
@@ -78,20 +76,25 @@ static struct program *program_load_sparse(struct program *program, int fd)
|
||||
* for a partition node but lacks a sparse header,
|
||||
* it will be validated against the defined partition size.
|
||||
* If the sizes match, it is likely that the 'sparse="true"' attribute
|
||||
* was set by mistake.
|
||||
* was set by mistake, fix the sparse flag and add the
|
||||
* program entry to the list.
|
||||
*/
|
||||
if ((off_t)program->sector_size * program->num_sectors ==
|
||||
lseek(fd, 0, SEEK_END)) {
|
||||
program_sparse = calloc(1, sizeof(struct program));
|
||||
memcpy(program_sparse, program, sizeof(struct program));
|
||||
program_sparse->sparse = false;
|
||||
program_sparse->next = NULL;
|
||||
return program_sparse;
|
||||
program->sparse = false;
|
||||
|
||||
if (programes) {
|
||||
programes_last->next = program;
|
||||
programes_last = program;
|
||||
} else {
|
||||
programes = program;
|
||||
programes_last = program;
|
||||
}
|
||||
}
|
||||
|
||||
ux_err("[PROGRAM] Unable to parse sparse header at %s...failed\n",
|
||||
program->filename);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sparse_header.total_chunks; ++i) {
|
||||
@@ -102,7 +105,7 @@ static struct program *program_load_sparse(struct program *program, int fd)
|
||||
if (chunk_type < 0) {
|
||||
ux_err("[PROGRAM] Unable to parse sparse chunk %i at %s...failed\n",
|
||||
i, program->filename);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chunk_size == 0)
|
||||
@@ -111,7 +114,7 @@ static struct program *program_load_sparse(struct program *program, int fd)
|
||||
if (chunk_size % program->sector_size != 0) {
|
||||
ux_err("[SPARSE] File chunk #%u size %" PRIu64 " is not a sector-multiple\n",
|
||||
i, chunk_size);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chunk_size / program->sector_size >= UINT_MAX) {
|
||||
@@ -121,51 +124,39 @@ static struct program *program_load_sparse(struct program *program, int fd)
|
||||
*/
|
||||
ux_err("[SPARSE] File chunk #%u size %" PRIu64 " is too large\n",
|
||||
i, chunk_size);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (chunk_type) {
|
||||
case CHUNK_TYPE_RAW:
|
||||
if (chunk_type == CHUNK_TYPE_RAW || chunk_type == CHUNK_TYPE_FILL) {
|
||||
program_sparse = calloc(1, sizeof(struct program));
|
||||
memcpy(program_sparse, program, sizeof(struct program));
|
||||
program_sparse->pages_per_block = program->pages_per_block;
|
||||
program_sparse->sector_size = program->sector_size;
|
||||
program_sparse->file_offset = program->file_offset;
|
||||
program_sparse->filename = strdup(program->filename);
|
||||
program_sparse->label = strdup(program->label);
|
||||
program_sparse->partition = program->partition;
|
||||
program_sparse->sparse = program->sparse;
|
||||
program_sparse->start_sector = strdup(program->start_sector);
|
||||
program_sparse->last_sector = program->last_sector;
|
||||
program_sparse->is_nand = program->is_nand;
|
||||
program_sparse->is_erase = false;
|
||||
|
||||
program_sparse->next = NULL;
|
||||
program_sparse->sparse_chunk_type = chunk_type;
|
||||
program_sparse->num_sectors = chunk_size / program->sector_size;
|
||||
|
||||
program_sparse->sparse_chunk_type = CHUNK_TYPE_RAW;
|
||||
program_sparse->sparse_offset = sparse_offset;
|
||||
|
||||
if (programes_sparse) {
|
||||
programes_sparse_last->next = program_sparse;
|
||||
programes_sparse_last = program_sparse;
|
||||
} else {
|
||||
programes_sparse = program_sparse;
|
||||
programes_sparse_last = program_sparse;
|
||||
}
|
||||
|
||||
break;
|
||||
case CHUNK_TYPE_FILL:
|
||||
|
||||
program_sparse = calloc(1, sizeof(struct program));
|
||||
memcpy(program_sparse, program, sizeof(struct program));
|
||||
if (chunk_type == CHUNK_TYPE_RAW)
|
||||
program_sparse->sparse_offset = sparse_offset;
|
||||
else
|
||||
program_sparse->sparse_fill_value = sparse_fill_value;
|
||||
|
||||
program_sparse->next = NULL;
|
||||
program_sparse->num_sectors = chunk_size / program->sector_size;
|
||||
|
||||
program_sparse->sparse_chunk_type = CHUNK_TYPE_FILL;
|
||||
program_sparse->sparse_fill_value = sparse_fill_value;
|
||||
|
||||
if (programes_sparse) {
|
||||
programes_sparse_last->next = program_sparse;
|
||||
programes_sparse_last = program_sparse;
|
||||
if (programes) {
|
||||
programes_last->next = program_sparse;
|
||||
programes_last = program_sparse;
|
||||
} else {
|
||||
programes_sparse = program_sparse;
|
||||
programes_sparse_last = program_sparse;
|
||||
programes = program_sparse;
|
||||
programes_last = program_sparse;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
start_sector = (unsigned int)strtoul(program->start_sector, NULL, 0);
|
||||
@@ -174,7 +165,7 @@ static struct program *program_load_sparse(struct program *program, int fd)
|
||||
program->start_sector = strdup(tmp);
|
||||
}
|
||||
|
||||
return programes_sparse;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_program_tag(xmlNode *node, bool is_nand, bool allow_missing, const char *incdir)
|
||||
@@ -182,7 +173,8 @@ static int load_program_tag(xmlNode *node, bool is_nand, bool allow_missing, con
|
||||
struct program *program;
|
||||
char tmp[PATH_MAX];
|
||||
int errors = 0;
|
||||
int fd;
|
||||
int ret;
|
||||
int fd = -1;
|
||||
|
||||
program = calloc(1, sizeof(struct program));
|
||||
|
||||
@@ -232,7 +224,19 @@ static int load_program_tag(xmlNode *node, bool is_nand, bool allow_missing, con
|
||||
free((void *)program->filename);
|
||||
program->filename = NULL;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (fd >= 0 && program->sparse) {
|
||||
ret = program_load_sparse(program, fd);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Chunks were added to the program list, drop the filename of
|
||||
* the parent, to prevent this from being written to the device
|
||||
*/
|
||||
free((void *)program->filename);
|
||||
program->filename = NULL;
|
||||
}
|
||||
|
||||
if (programes) {
|
||||
@@ -243,6 +247,9 @@ static int load_program_tag(xmlNode *node, bool is_nand, bool allow_missing, con
|
||||
programes_last = program;
|
||||
}
|
||||
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -286,7 +293,6 @@ out:
|
||||
int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd))
|
||||
{
|
||||
struct program *program;
|
||||
struct program *program_sparse;
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
@@ -301,22 +307,7 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!program->sparse) {
|
||||
ret = apply(qdl, program, fd);
|
||||
} else {
|
||||
program_sparse = program_load_sparse(program, fd);
|
||||
if (!program_sparse) {
|
||||
ux_err("[PROGRAM] load sparse failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (; program_sparse; program_sparse = program_sparse->next) {
|
||||
ret = apply(qdl, program_sparse, fd);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = apply(qdl, program, fd);
|
||||
close(fd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user