openwrtv4/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c
Rafał Miłecki 1a57ce0c03 kernel: mtdsplit: add missing digest field to Seama header
Seama format has 2 similar headers: container (seal) header and entity
header. The first one has size always set to 0 and doesn't contain MD5
digest.

When dealing with Seama on a flash we deal directly with an entity. You
can see mtdsplit_parse_seama reads from offset 0 and expects entity to
be there. Seama container is used by bootloader / interface only which
extract entity out of it and flash it.

That said we should fix our header struct. This is important as we
calculate possible rootfs offset assuming it may be placed right after
Seama entity. So far calculate offset was always 16B too low.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>

SVN-Revision: 48754
2016-02-23 14:40:40 +00:00

110 lines
2.7 KiB
C

/*
* Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/byteorder/generic.h>
#include "mtdsplit.h"
#define SEAMA_MAGIC 0x5EA3A417
#define SEAMA_NR_PARTS 2
#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */
struct seama_header {
__be32 magic; /* should always be SEAMA_MAGIC. */
__be16 reserved; /* reserved for */
__be16 metasize; /* size of the META data */
__be32 size; /* size of the image */
u8 md5[16]; /* digest */
};
static int mtdsplit_parse_seama(struct mtd_info *master,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct seama_header hdr;
size_t hdr_len, retlen, kernel_ent_size;
size_t rootfs_offset;
struct mtd_partition *parts;
enum mtdsplit_part_type type;
int err;
hdr_len = sizeof(hdr);
err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
if (err)
return err;
if (retlen != hdr_len)
return -EIO;
/* sanity checks */
if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC)
return -EINVAL;
kernel_ent_size = hdr_len + be32_to_cpu(hdr.size) +
be16_to_cpu(hdr.metasize);
if (kernel_ent_size > master->size)
return -EINVAL;
/* Check for the rootfs right after Seama entity with a kernel. */
err = mtd_check_rootfs_magic(master, kernel_ent_size, &type);
if (!err) {
rootfs_offset = kernel_ent_size;
} else {
/*
* On some devices firmware entity might contain both: kernel
* and rootfs. We can't determine kernel size so we just have to
* look for rootfs magic.
* Start the search from an arbitrary offset.
*/
err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS,
master->size, &rootfs_offset, &type);
if (err)
return err;
}
parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
if (!parts)
return -ENOMEM;
parts[0].name = KERNEL_PART_NAME;
parts[0].offset = 0;
parts[0].size = rootfs_offset;
if (type == MTDSPLIT_PART_TYPE_UBI)
parts[1].name = UBI_PART_NAME;
else
parts[1].name = ROOTFS_PART_NAME;
parts[1].offset = rootfs_offset;
parts[1].size = master->size - rootfs_offset;
*pparts = parts;
return SEAMA_NR_PARTS;
}
static struct mtd_part_parser mtdsplit_seama_parser = {
.owner = THIS_MODULE,
.name = "seama-fw",
.parse_fn = mtdsplit_parse_seama,
.type = MTD_PARSER_TYPE_FIRMWARE,
};
static int __init mtdsplit_seama_init(void)
{
register_mtd_parser(&mtdsplit_seama_parser);
return 0;
}
subsys_initcall(mtdsplit_seama_init);