xref: /openbmc/linux/drivers/mtd/parsers/parser_trx.c (revision 99352afe8f169c95b294b6b9a8d0e18cd9e3c2a0)
1*99352afeSRafał Miłecki /*
2*99352afeSRafał Miłecki  * Parser for TRX format partitions
3*99352afeSRafał Miłecki  *
4*99352afeSRafał Miłecki  * Copyright (C) 2012 - 2017 Rafał Miłecki <rafal@milecki.pl>
5*99352afeSRafał Miłecki  *
6*99352afeSRafał Miłecki  * This program is free software; you can redistribute it and/or modify
7*99352afeSRafał Miłecki  * it under the terms of the GNU General Public License version 2 as
8*99352afeSRafał Miłecki  * published by the Free Software Foundation.
9*99352afeSRafał Miłecki  *
10*99352afeSRafał Miłecki  */
11*99352afeSRafał Miłecki 
12*99352afeSRafał Miłecki #include <linux/module.h>
13*99352afeSRafał Miłecki #include <linux/slab.h>
14*99352afeSRafał Miłecki #include <linux/mtd/mtd.h>
15*99352afeSRafał Miłecki #include <linux/mtd/partitions.h>
16*99352afeSRafał Miłecki 
17*99352afeSRafał Miłecki #define TRX_PARSER_MAX_PARTS		4
18*99352afeSRafał Miłecki 
19*99352afeSRafał Miłecki /* Magics */
20*99352afeSRafał Miłecki #define TRX_MAGIC			0x30524448
21*99352afeSRafał Miłecki #define UBI_EC_MAGIC			0x23494255	/* UBI# */
22*99352afeSRafał Miłecki 
23*99352afeSRafał Miłecki struct trx_header {
24*99352afeSRafał Miłecki 	uint32_t magic;
25*99352afeSRafał Miłecki 	uint32_t length;
26*99352afeSRafał Miłecki 	uint32_t crc32;
27*99352afeSRafał Miłecki 	uint16_t flags;
28*99352afeSRafał Miłecki 	uint16_t version;
29*99352afeSRafał Miłecki 	uint32_t offset[3];
30*99352afeSRafał Miłecki } __packed;
31*99352afeSRafał Miłecki 
32*99352afeSRafał Miłecki static const char *parser_trx_data_part_name(struct mtd_info *master,
33*99352afeSRafał Miłecki 					     size_t offset)
34*99352afeSRafał Miłecki {
35*99352afeSRafał Miłecki 	uint32_t buf;
36*99352afeSRafał Miłecki 	size_t bytes_read;
37*99352afeSRafał Miłecki 	int err;
38*99352afeSRafał Miłecki 
39*99352afeSRafał Miłecki 	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
40*99352afeSRafał Miłecki 			(uint8_t *)&buf);
41*99352afeSRafał Miłecki 	if (err && !mtd_is_bitflip(err)) {
42*99352afeSRafał Miłecki 		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
43*99352afeSRafał Miłecki 			offset, err);
44*99352afeSRafał Miłecki 		goto out_default;
45*99352afeSRafał Miłecki 	}
46*99352afeSRafał Miłecki 
47*99352afeSRafał Miłecki 	if (buf == UBI_EC_MAGIC)
48*99352afeSRafał Miłecki 		return "ubi";
49*99352afeSRafał Miłecki 
50*99352afeSRafał Miłecki out_default:
51*99352afeSRafał Miłecki 	return "rootfs";
52*99352afeSRafał Miłecki }
53*99352afeSRafał Miłecki 
54*99352afeSRafał Miłecki static int parser_trx_parse(struct mtd_info *mtd,
55*99352afeSRafał Miłecki 			    const struct mtd_partition **pparts,
56*99352afeSRafał Miłecki 			    struct mtd_part_parser_data *data)
57*99352afeSRafał Miłecki {
58*99352afeSRafał Miłecki 	struct mtd_partition *parts;
59*99352afeSRafał Miłecki 	struct mtd_partition *part;
60*99352afeSRafał Miłecki 	struct trx_header trx;
61*99352afeSRafał Miłecki 	size_t bytes_read;
62*99352afeSRafał Miłecki 	uint8_t curr_part = 0, i = 0;
63*99352afeSRafał Miłecki 	int err;
64*99352afeSRafał Miłecki 
65*99352afeSRafał Miłecki 	parts = kzalloc(sizeof(struct mtd_partition) * TRX_PARSER_MAX_PARTS,
66*99352afeSRafał Miłecki 			GFP_KERNEL);
67*99352afeSRafał Miłecki 	if (!parts)
68*99352afeSRafał Miłecki 		return -ENOMEM;
69*99352afeSRafał Miłecki 
70*99352afeSRafał Miłecki 	err = mtd_read(mtd, 0, sizeof(trx), &bytes_read, (uint8_t *)&trx);
71*99352afeSRafał Miłecki 	if (err) {
72*99352afeSRafał Miłecki 		pr_err("MTD reading error: %d\n", err);
73*99352afeSRafał Miłecki 		kfree(parts);
74*99352afeSRafał Miłecki 		return err;
75*99352afeSRafał Miłecki 	}
76*99352afeSRafał Miłecki 
77*99352afeSRafał Miłecki 	if (trx.magic != TRX_MAGIC) {
78*99352afeSRafał Miłecki 		kfree(parts);
79*99352afeSRafał Miłecki 		return -ENOENT;
80*99352afeSRafał Miłecki 	}
81*99352afeSRafał Miłecki 
82*99352afeSRafał Miłecki 	/* We have LZMA loader if there is address in offset[2] */
83*99352afeSRafał Miłecki 	if (trx.offset[2]) {
84*99352afeSRafał Miłecki 		part = &parts[curr_part++];
85*99352afeSRafał Miłecki 		part->name = "loader";
86*99352afeSRafał Miłecki 		part->offset = trx.offset[i];
87*99352afeSRafał Miłecki 		i++;
88*99352afeSRafał Miłecki 	}
89*99352afeSRafał Miłecki 
90*99352afeSRafał Miłecki 	if (trx.offset[i]) {
91*99352afeSRafał Miłecki 		part = &parts[curr_part++];
92*99352afeSRafał Miłecki 		part->name = "linux";
93*99352afeSRafał Miłecki 		part->offset = trx.offset[i];
94*99352afeSRafał Miłecki 		i++;
95*99352afeSRafał Miłecki 	}
96*99352afeSRafał Miłecki 
97*99352afeSRafał Miłecki 	if (trx.offset[i]) {
98*99352afeSRafał Miłecki 		part = &parts[curr_part++];
99*99352afeSRafał Miłecki 		part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
100*99352afeSRafał Miłecki 		part->offset = trx.offset[i];
101*99352afeSRafał Miłecki 		i++;
102*99352afeSRafał Miłecki 	}
103*99352afeSRafał Miłecki 
104*99352afeSRafał Miłecki 	/*
105*99352afeSRafał Miłecki 	 * Assume that every partition ends at the beginning of the one it is
106*99352afeSRafał Miłecki 	 * followed by.
107*99352afeSRafał Miłecki 	 */
108*99352afeSRafał Miłecki 	for (i = 0; i < curr_part; i++) {
109*99352afeSRafał Miłecki 		u64 next_part_offset = (i < curr_part - 1) ?
110*99352afeSRafał Miłecki 				       parts[i + 1].offset : mtd->size;
111*99352afeSRafał Miłecki 
112*99352afeSRafał Miłecki 		parts[i].size = next_part_offset - parts[i].offset;
113*99352afeSRafał Miłecki 	}
114*99352afeSRafał Miłecki 
115*99352afeSRafał Miłecki 	*pparts = parts;
116*99352afeSRafał Miłecki 	return i;
117*99352afeSRafał Miłecki };
118*99352afeSRafał Miłecki 
119*99352afeSRafał Miłecki static struct mtd_part_parser mtd_parser_trx = {
120*99352afeSRafał Miłecki 	.parse_fn = parser_trx_parse,
121*99352afeSRafał Miłecki 	.name = "trx",
122*99352afeSRafał Miłecki };
123*99352afeSRafał Miłecki module_mtd_part_parser(mtd_parser_trx);
124*99352afeSRafał Miłecki 
125*99352afeSRafał Miłecki MODULE_LICENSE("GPL v2");
126*99352afeSRafał Miłecki MODULE_DESCRIPTION("Parser for TRX format partitions");
127