summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Gorski <jonas.gorski@gmail.com>2019-03-28 10:19:08 -0400
committerRichard Weinberger <richard@nod.at>2019-05-06 15:46:45 -0400
commitdd84cb022b310674f4c287ac426cb10f1b577140 (patch)
tree088070af45b8c7fa44494518a8283b49214b17cb
parente651de475a7a919403b51eb93db374d732377b0e (diff)
mtd: bcm63xxpart: move imagetag parsing to its own parser
Move the bcm963xx Image Tag parsing into its own partition parser. This Allows reusing the parser with different full flash parsers. While moving it, rename it to bcm963* to better reflect it isn't chip, but reference implementation specific. Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--drivers/mtd/Kconfig1
-rw-r--r--drivers/mtd/bcm63xxpart.c155
-rw-r--r--drivers/mtd/parsers/Kconfig11
-rw-r--r--drivers/mtd/parsers/Makefile1
-rw-r--r--drivers/mtd/parsers/parser_imagetag.c214
5 files changed, 235 insertions, 147 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index aa5a27fdfdd1..0c263df7ded7 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -94,6 +94,7 @@ config MTD_BCM63XX_PARTS
94 tristate "BCM63XX CFE partitioning support" 94 tristate "BCM63XX CFE partitioning support"
95 depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST 95 depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
96 select CRC32 96 select CRC32
97 select MTD_PARSER_IMAGETAG
97 help 98 help
98 This provides partition parsing for BCM63xx devices with CFE 99 This provides partition parsing for BCM63xx devices with CFE
99 bootloaders. 100 bootloaders.
diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c
index f639b4c960f0..b2bd04764e95 100644
--- a/drivers/mtd/bcm63xxpart.c
+++ b/drivers/mtd/bcm63xxpart.c
@@ -94,51 +94,19 @@ static int bcm63xx_read_nvram(struct mtd_info *master,
94 return 0; 94 return 0;
95} 95}
96 96
97static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name, 97static const char * const bcm63xx_cfe_part_types[] = {
98 loff_t tag_offset, struct bcm_tag *buf) 98 "bcm963xx-imagetag",
99{ 99 NULL,
100 int ret; 100};
101 size_t retlen;
102 u32 computed_crc;
103
104 ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
105 if (ret)
106 return ret;
107
108 if (retlen != sizeof(*buf))
109 return -EIO;
110
111 computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
112 offsetof(struct bcm_tag, header_crc));
113 if (computed_crc == buf->header_crc) {
114 STR_NULL_TERMINATE(buf->board_id);
115 STR_NULL_TERMINATE(buf->tag_version);
116
117 pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
118 name, tag_offset, buf->tag_version, buf->board_id);
119
120 return 0;
121 }
122
123 pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
124 name, tag_offset, buf->header_crc, computed_crc);
125 return 1;
126}
127 101
128static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master, 102static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
129 const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram) 103 const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
130{ 104{
131 /* CFE, NVRAM and global Linux are always present */
132 int nrparts = 3, curpart = 0;
133 struct bcm_tag *buf = NULL;
134 struct mtd_partition *parts; 105 struct mtd_partition *parts;
135 int ret; 106 int nrparts = 3, curpart = 0;
136 unsigned int rootfsaddr, kerneladdr, spareaddr;
137 unsigned int rootfslen, kernellen, sparelen, totallen;
138 unsigned int cfelen, nvramlen; 107 unsigned int cfelen, nvramlen;
139 unsigned int cfe_erasesize; 108 unsigned int cfe_erasesize;
140 int i; 109 int i;
141 bool rootfs_first = false;
142 110
143 cfe_erasesize = max_t(uint32_t, master->erasesize, 111 cfe_erasesize = max_t(uint32_t, master->erasesize,
144 BCM963XX_CFE_BLOCK_SIZE); 112 BCM963XX_CFE_BLOCK_SIZE);
@@ -147,83 +115,9 @@ static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
147 nvramlen = nvram->psi_size * SZ_1K; 115 nvramlen = nvram->psi_size * SZ_1K;
148 nvramlen = roundup(nvramlen, cfe_erasesize); 116 nvramlen = roundup(nvramlen, cfe_erasesize);
149 117
150 buf = vmalloc(sizeof(struct bcm_tag));
151 if (!buf)
152 return -ENOMEM;
153
154 /* Get the tag */
155 ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
156 if (!ret) {
157 STR_NULL_TERMINATE(buf->flash_image_start);
158 if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
159 rootfsaddr < BCM963XX_EXTENDED_SIZE) {
160 pr_err("invalid rootfs address: %*ph\n",
161 (int)sizeof(buf->flash_image_start),
162 buf->flash_image_start);
163 goto invalid_tag;
164 }
165
166 STR_NULL_TERMINATE(buf->kernel_address);
167 if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
168 kerneladdr < BCM963XX_EXTENDED_SIZE) {
169 pr_err("invalid kernel address: %*ph\n",
170 (int)sizeof(buf->kernel_address),
171 buf->kernel_address);
172 goto invalid_tag;
173 }
174
175 STR_NULL_TERMINATE(buf->kernel_length);
176 if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
177 pr_err("invalid kernel length: %*ph\n",
178 (int)sizeof(buf->kernel_length),
179 buf->kernel_length);
180 goto invalid_tag;
181 }
182
183 STR_NULL_TERMINATE(buf->total_length);
184 if (kstrtouint(buf->total_length, 10, &totallen)) {
185 pr_err("invalid total length: %*ph\n",
186 (int)sizeof(buf->total_length),
187 buf->total_length);
188 goto invalid_tag;
189 }
190
191 kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
192 rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
193 spareaddr = roundup(totallen, master->erasesize) + cfelen;
194
195 if (rootfsaddr < kerneladdr) {
196 /* default Broadcom layout */
197 rootfslen = kerneladdr - rootfsaddr;
198 rootfs_first = true;
199 } else {
200 /* OpenWrt layout */
201 rootfsaddr = kerneladdr + kernellen;
202 rootfslen = spareaddr - rootfsaddr;
203 }
204 } else if (ret > 0) {
205invalid_tag:
206 kernellen = 0;
207 rootfslen = 0;
208 rootfsaddr = 0;
209 spareaddr = cfelen;
210 } else {
211 goto out;
212 }
213 sparelen = master->size - spareaddr - nvramlen;
214
215 /* Determine number of partitions */
216 if (rootfslen > 0)
217 nrparts++;
218
219 if (kernellen > 0)
220 nrparts++;
221
222 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); 118 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
223 if (!parts) { 119 if (!parts)
224 ret = -ENOMEM; 120 return -ENOMEM;
225 goto out;
226 }
227 121
228 /* Start building partition list */ 122 /* Start building partition list */
229 parts[curpart].name = "CFE"; 123 parts[curpart].name = "CFE";
@@ -231,30 +125,6 @@ invalid_tag:
231 parts[curpart].size = cfelen; 125 parts[curpart].size = cfelen;
232 curpart++; 126 curpart++;
233 127
234 if (kernellen > 0) {
235 int kernelpart = curpart;
236
237 if (rootfslen > 0 && rootfs_first)
238 kernelpart++;
239 parts[kernelpart].name = "kernel";
240 parts[kernelpart].offset = kerneladdr;
241 parts[kernelpart].size = kernellen;
242 curpart++;
243 }
244
245 if (rootfslen > 0) {
246 int rootfspart = curpart;
247
248 if (kernellen > 0 && rootfs_first)
249 rootfspart--;
250 parts[rootfspart].name = "rootfs";
251 parts[rootfspart].offset = rootfsaddr;
252 parts[rootfspart].size = rootfslen;
253 if (sparelen > 0 && !rootfs_first)
254 parts[rootfspart].size += sparelen;
255 curpart++;
256 }
257
258 parts[curpart].name = "nvram"; 128 parts[curpart].name = "nvram";
259 parts[curpart].offset = master->size - nvramlen; 129 parts[curpart].offset = master->size - nvramlen;
260 parts[curpart].size = nvramlen; 130 parts[curpart].size = nvramlen;
@@ -264,22 +134,13 @@ invalid_tag:
264 parts[curpart].name = "linux"; 134 parts[curpart].name = "linux";
265 parts[curpart].offset = cfelen; 135 parts[curpart].offset = cfelen;
266 parts[curpart].size = master->size - cfelen - nvramlen; 136 parts[curpart].size = master->size - cfelen - nvramlen;
137 parts[curpart].types = bcm63xx_cfe_part_types;
267 138
268 for (i = 0; i < nrparts; i++) 139 for (i = 0; i < nrparts; i++)
269 pr_info("Partition %d is %s offset %llx and length %llx\n", i, 140 pr_info("Partition %d is %s offset %llx and length %llx\n", i,
270 parts[i].name, parts[i].offset, parts[i].size); 141 parts[i].name, parts[i].offset, parts[i].size);
271 142
272 pr_info("Spare partition is offset %x and length %x\n", spareaddr,
273 sparelen);
274
275 *pparts = parts; 143 *pparts = parts;
276 ret = 0;
277
278out:
279 vfree(buf);
280
281 if (ret)
282 return ret;
283 144
284 return nrparts; 145 return nrparts;
285} 146}
diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig
index fccf1950e92d..c8be3f1507ca 100644
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -1,3 +1,14 @@
1config MTD_PARSER_IMAGETAG
2 tristate "Parser for BCM963XX Image Tag format partitions"
3 depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
4 select CRC32
5 help
6 Image Tag is the firmware header used by broadcom on their xDSL line
7 of devices. It is used to describe the offsets and lengths of kernel
8 and rootfs partitions.
9 This driver adds support for parsing a partition with an Image Tag
10 header and creates up to two partitions, kernel and rootfs.
11
1config MTD_PARSER_TRX 12config MTD_PARSER_TRX
2 tristate "Parser for TRX format partitions" 13 tristate "Parser for TRX format partitions"
3 depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST) 14 depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST)
diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile
index d8418bf6804a..3860c4464c63 100644
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
1obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o 2obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
2obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o 3obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
3obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o 4obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
diff --git a/drivers/mtd/parsers/parser_imagetag.c b/drivers/mtd/parsers/parser_imagetag.c
new file mode 100644
index 000000000000..74b66d009b5c
--- /dev/null
+++ b/drivers/mtd/parsers/parser_imagetag.c
@@ -0,0 +1,214 @@
1/*
2 * BCM63XX CFE image tag parser
3 *
4 * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
5 * Mike Albon <malbon@openwrt.org>
6 * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
7 * Copyright © 2011-2013 Jonas Gorski <jonas.gorski@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 */
15
16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18#include <linux/bcm963xx_tag.h>
19#include <linux/crc32.h>
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/sizes.h>
23#include <linux/slab.h>
24#include <linux/vmalloc.h>
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/partitions.h>
27
28/* Ensure strings read from flash structs are null terminated */
29#define STR_NULL_TERMINATE(x) \
30 do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
31
32static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name,
33 loff_t tag_offset, struct bcm_tag *buf)
34{
35 int ret;
36 size_t retlen;
37 u32 computed_crc;
38
39 ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
40 if (ret)
41 return ret;
42
43 if (retlen != sizeof(*buf))
44 return -EIO;
45
46 computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
47 offsetof(struct bcm_tag, header_crc));
48 if (computed_crc == buf->header_crc) {
49 STR_NULL_TERMINATE(buf->board_id);
50 STR_NULL_TERMINATE(buf->tag_version);
51
52 pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
53 name, tag_offset, buf->tag_version, buf->board_id);
54
55 return 0;
56 }
57
58 pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
59 name, tag_offset, buf->header_crc, computed_crc);
60 return -EINVAL;
61}
62
63static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master,
64 const struct mtd_partition **pparts,
65 struct mtd_part_parser_data *data)
66{
67 /* CFE, NVRAM and global Linux are always present */
68 int nrparts = 0, curpart = 0;
69 struct bcm_tag *buf = NULL;
70 struct mtd_partition *parts;
71 int ret;
72 unsigned int rootfsaddr, kerneladdr, spareaddr, offset;
73 unsigned int rootfslen, kernellen, sparelen, totallen;
74 int i;
75 bool rootfs_first = false;
76
77 buf = vmalloc(sizeof(struct bcm_tag));
78 if (!buf)
79 return -ENOMEM;
80
81 /* Get the tag */
82 ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf);
83 if (!ret) {
84 STR_NULL_TERMINATE(buf->flash_image_start);
85 if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
86 rootfsaddr < BCM963XX_EXTENDED_SIZE) {
87 pr_err("invalid rootfs address: %*ph\n",
88 (int)sizeof(buf->flash_image_start),
89 buf->flash_image_start);
90 goto out;
91 }
92
93 STR_NULL_TERMINATE(buf->kernel_address);
94 if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
95 kerneladdr < BCM963XX_EXTENDED_SIZE) {
96 pr_err("invalid kernel address: %*ph\n",
97 (int)sizeof(buf->kernel_address),
98 buf->kernel_address);
99 goto out;
100 }
101
102 STR_NULL_TERMINATE(buf->kernel_length);
103 if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
104 pr_err("invalid kernel length: %*ph\n",
105 (int)sizeof(buf->kernel_length),
106 buf->kernel_length);
107 goto out;
108 }
109
110 STR_NULL_TERMINATE(buf->total_length);
111 if (kstrtouint(buf->total_length, 10, &totallen)) {
112 pr_err("invalid total length: %*ph\n",
113 (int)sizeof(buf->total_length),
114 buf->total_length);
115 goto out;
116 }
117
118 /*
119 * Addresses are flash absolute, so convert to partition
120 * relative addresses. Assume either kernel or rootfs will
121 * directly follow the image tag.
122 */
123 if (rootfsaddr < kerneladdr)
124 offset = rootfsaddr - sizeof(struct bcm_tag);
125 else
126 offset = kerneladdr - sizeof(struct bcm_tag);
127
128 kerneladdr = kerneladdr - offset;
129 rootfsaddr = rootfsaddr - offset;
130 spareaddr = roundup(totallen, master->erasesize);
131
132 if (rootfsaddr < kerneladdr) {
133 /* default Broadcom layout */
134 rootfslen = kerneladdr - rootfsaddr;
135 rootfs_first = true;
136 } else {
137 /* OpenWrt layout */
138 rootfsaddr = kerneladdr + kernellen;
139 rootfslen = spareaddr - rootfsaddr;
140 }
141 } else {
142 goto out;
143 }
144 sparelen = master->size - spareaddr;
145
146 /* Determine number of partitions */
147 if (rootfslen > 0)
148 nrparts++;
149
150 if (kernellen > 0)
151 nrparts++;
152
153 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
154 if (!parts) {
155 ret = -ENOMEM;
156 goto out;
157 }
158
159 /* Start building partition list */
160 if (kernellen > 0) {
161 int kernelpart = curpart;
162
163 if (rootfslen > 0 && rootfs_first)
164 kernelpart++;
165 parts[kernelpart].name = "kernel";
166 parts[kernelpart].offset = kerneladdr;
167 parts[kernelpart].size = kernellen;
168 curpart++;
169 }
170
171 if (rootfslen > 0) {
172 int rootfspart = curpart;
173
174 if (kernellen > 0 && rootfs_first)
175 rootfspart--;
176 parts[rootfspart].name = "rootfs";
177 parts[rootfspart].offset = rootfsaddr;
178 parts[rootfspart].size = rootfslen;
179 if (sparelen > 0 && !rootfs_first)
180 parts[rootfspart].size += sparelen;
181 curpart++;
182 }
183
184 for (i = 0; i < nrparts; i++)
185 pr_info("Partition %d is %s offset %llx and length %llx\n", i,
186 parts[i].name, parts[i].offset, parts[i].size);
187
188 pr_info("Spare partition is offset %x and length %x\n", spareaddr,
189 sparelen);
190
191 *pparts = parts;
192 ret = 0;
193
194out:
195 vfree(buf);
196
197 if (ret)
198 return ret;
199
200 return nrparts;
201}
202
203static struct mtd_part_parser bcm963xx_imagetag_parser = {
204 .parse_fn = bcm963xx_parse_imagetag_partitions,
205 .name = "bcm963xx-imagetag",
206};
207module_mtd_part_parser(bcm963xx_imagetag_parser);
208
209MODULE_LICENSE("GPL");
210MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
211MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
212MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
213MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com>");
214MODULE_DESCRIPTION("MTD parser for BCM963XX CFE Image Tag partitions");