xref: /openbmc/linux/drivers/mtd/parsers/parser_trx.c (revision 98534a58c8a40cdc9e3bcb04d74719fbcedfeb52)
199352afeSRafał Miłecki /*
299352afeSRafał Miłecki  * Parser for TRX format partitions
399352afeSRafał Miłecki  *
499352afeSRafał Miłecki  * Copyright (C) 2012 - 2017 Rafał Miłecki <rafal@milecki.pl>
599352afeSRafał Miłecki  *
699352afeSRafał Miłecki  * This program is free software; you can redistribute it and/or modify
799352afeSRafał Miłecki  * it under the terms of the GNU General Public License version 2 as
899352afeSRafał Miłecki  * published by the Free Software Foundation.
999352afeSRafał Miłecki  *
1099352afeSRafał Miłecki  */
1199352afeSRafał Miłecki 
1299352afeSRafał Miłecki #include <linux/module.h>
1399352afeSRafał Miłecki #include <linux/slab.h>
1499352afeSRafał Miłecki #include <linux/mtd/mtd.h>
1599352afeSRafał Miłecki #include <linux/mtd/partitions.h>
1699352afeSRafał Miłecki 
1799352afeSRafał Miłecki #define TRX_PARSER_MAX_PARTS		4
1899352afeSRafał Miłecki 
1999352afeSRafał Miłecki /* Magics */
2099352afeSRafał Miłecki #define TRX_MAGIC			0x30524448
2199352afeSRafał Miłecki #define UBI_EC_MAGIC			0x23494255	/* UBI# */
2299352afeSRafał Miłecki 
2399352afeSRafał Miłecki struct trx_header {
2499352afeSRafał Miłecki 	uint32_t magic;
2599352afeSRafał Miłecki 	uint32_t length;
2699352afeSRafał Miłecki 	uint32_t crc32;
2799352afeSRafał Miłecki 	uint16_t flags;
2899352afeSRafał Miłecki 	uint16_t version;
2999352afeSRafał Miłecki 	uint32_t offset[3];
3099352afeSRafał Miłecki } __packed;
3199352afeSRafał Miłecki 
3299352afeSRafał Miłecki static const char *parser_trx_data_part_name(struct mtd_info *master,
3399352afeSRafał Miłecki 					     size_t offset)
3499352afeSRafał Miłecki {
3599352afeSRafał Miłecki 	uint32_t buf;
3699352afeSRafał Miłecki 	size_t bytes_read;
3799352afeSRafał Miłecki 	int err;
3899352afeSRafał Miłecki 
3999352afeSRafał Miłecki 	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
4099352afeSRafał Miłecki 			(uint8_t *)&buf);
4199352afeSRafał Miłecki 	if (err && !mtd_is_bitflip(err)) {
4258de51caSRafał Miłecki 		pr_err("mtd_read error while parsing (offset: 0x%zX): %d\n",
4399352afeSRafał Miłecki 			offset, err);
4499352afeSRafał Miłecki 		goto out_default;
4599352afeSRafał Miłecki 	}
4699352afeSRafał Miłecki 
4799352afeSRafał Miłecki 	if (buf == UBI_EC_MAGIC)
4899352afeSRafał Miłecki 		return "ubi";
4999352afeSRafał Miłecki 
5099352afeSRafał Miłecki out_default:
5199352afeSRafał Miłecki 	return "rootfs";
5299352afeSRafał Miłecki }
5399352afeSRafał Miłecki 
5499352afeSRafał Miłecki static int parser_trx_parse(struct mtd_info *mtd,
5599352afeSRafał Miłecki 			    const struct mtd_partition **pparts,
5699352afeSRafał Miłecki 			    struct mtd_part_parser_data *data)
5799352afeSRafał Miłecki {
5899352afeSRafał Miłecki 	struct mtd_partition *parts;
5999352afeSRafał Miłecki 	struct mtd_partition *part;
6099352afeSRafał Miłecki 	struct trx_header trx;
6199352afeSRafał Miłecki 	size_t bytes_read;
6299352afeSRafał Miłecki 	uint8_t curr_part = 0, i = 0;
6399352afeSRafał Miłecki 	int err;
6499352afeSRafał Miłecki 
656396bb22SKees Cook 	parts = kcalloc(TRX_PARSER_MAX_PARTS, sizeof(struct mtd_partition),
6699352afeSRafał Miłecki 			GFP_KERNEL);
6799352afeSRafał Miłecki 	if (!parts)
6899352afeSRafał Miłecki 		return -ENOMEM;
6999352afeSRafał Miłecki 
7099352afeSRafał Miłecki 	err = mtd_read(mtd, 0, sizeof(trx), &bytes_read, (uint8_t *)&trx);
7199352afeSRafał Miłecki 	if (err) {
7299352afeSRafał Miłecki 		pr_err("MTD reading error: %d\n", err);
7399352afeSRafał Miłecki 		kfree(parts);
7499352afeSRafał Miłecki 		return err;
7599352afeSRafał Miłecki 	}
7699352afeSRafał Miłecki 
7799352afeSRafał Miłecki 	if (trx.magic != TRX_MAGIC) {
7899352afeSRafał Miłecki 		kfree(parts);
7999352afeSRafał Miłecki 		return -ENOENT;
8099352afeSRafał Miłecki 	}
8199352afeSRafał Miłecki 
8299352afeSRafał Miłecki 	/* We have LZMA loader if there is address in offset[2] */
8399352afeSRafał Miłecki 	if (trx.offset[2]) {
8499352afeSRafał Miłecki 		part = &parts[curr_part++];
8599352afeSRafał Miłecki 		part->name = "loader";
8699352afeSRafał Miłecki 		part->offset = trx.offset[i];
8799352afeSRafał Miłecki 		i++;
8899352afeSRafał Miłecki 	}
8999352afeSRafał Miłecki 
9099352afeSRafał Miłecki 	if (trx.offset[i]) {
9199352afeSRafał Miłecki 		part = &parts[curr_part++];
9299352afeSRafał Miłecki 		part->name = "linux";
9399352afeSRafał Miłecki 		part->offset = trx.offset[i];
9499352afeSRafał Miłecki 		i++;
9599352afeSRafał Miłecki 	}
9699352afeSRafał Miłecki 
9799352afeSRafał Miłecki 	if (trx.offset[i]) {
9899352afeSRafał Miłecki 		part = &parts[curr_part++];
9999352afeSRafał Miłecki 		part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
10099352afeSRafał Miłecki 		part->offset = trx.offset[i];
10199352afeSRafał Miłecki 		i++;
10299352afeSRafał Miłecki 	}
10399352afeSRafał Miłecki 
10499352afeSRafał Miłecki 	/*
10599352afeSRafał Miłecki 	 * Assume that every partition ends at the beginning of the one it is
10699352afeSRafał Miłecki 	 * followed by.
10799352afeSRafał Miłecki 	 */
10899352afeSRafał Miłecki 	for (i = 0; i < curr_part; i++) {
10999352afeSRafał Miłecki 		u64 next_part_offset = (i < curr_part - 1) ?
11099352afeSRafał Miłecki 				       parts[i + 1].offset : mtd->size;
11199352afeSRafał Miłecki 
11299352afeSRafał Miłecki 		parts[i].size = next_part_offset - parts[i].offset;
11399352afeSRafał Miłecki 	}
11499352afeSRafał Miłecki 
11599352afeSRafał Miłecki 	*pparts = parts;
11699352afeSRafał Miłecki 	return i;
11799352afeSRafał Miłecki };
11899352afeSRafał Miłecki 
119*98534a58SRafał Miłecki static const struct of_device_id mtd_parser_trx_of_match_table[] = {
120*98534a58SRafał Miłecki 	{ .compatible = "brcm,trx" },
121*98534a58SRafał Miłecki 	{},
122*98534a58SRafał Miłecki };
123*98534a58SRafał Miłecki MODULE_DEVICE_TABLE(of, mtd_parser_trx_of_match_table);
124*98534a58SRafał Miłecki 
12599352afeSRafał Miłecki static struct mtd_part_parser mtd_parser_trx = {
12699352afeSRafał Miłecki 	.parse_fn = parser_trx_parse,
12799352afeSRafał Miłecki 	.name = "trx",
128*98534a58SRafał Miłecki 	.of_match_table = mtd_parser_trx_of_match_table,
12999352afeSRafał Miłecki };
13099352afeSRafał Miłecki module_mtd_part_parser(mtd_parser_trx);
13199352afeSRafał Miłecki 
13299352afeSRafał Miłecki MODULE_LICENSE("GPL v2");
13399352afeSRafał Miłecki MODULE_DESCRIPTION("Parser for TRX format partitions");
134