Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * BCM47XX MTD partitioning
  3 *
  4 * Copyright © 2012 Rafał Miłecki <zajec5@gmail.com>
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License version 2 as
  8 * published by the Free Software Foundation.
  9 *
 10 */
 11
 12#include <linux/module.h>
 13#include <linux/kernel.h>
 14#include <linux/slab.h>
 15#include <linux/mtd/mtd.h>
 16#include <linux/mtd/partitions.h>
 17
 18#include <uapi/linux/magic.h>
 19
 20/*
 21 * NAND flash on Netgear R6250 was verified to contain 15 partitions.
 22 * This will result in allocating too big array for some old devices, but the
 23 * memory will be freed soon anyway (see mtd_device_parse_register).
 24 */
 25#define BCM47XXPART_MAX_PARTS		20
 26
 27/*
 28 * Amount of bytes we read when analyzing each block of flash memory.
 29 * Set it big enough to allow detecting partition and reading important data.
 30 */
 31#define BCM47XXPART_BYTES_TO_READ	0x4e8
 32
 33/* Magics */
 34#define BOARD_DATA_MAGIC		0x5246504D	/* MPFR */
 35#define BOARD_DATA_MAGIC2		0xBD0D0BBD
 36#define CFE_MAGIC			0x43464531	/* 1EFC */
 37#define FACTORY_MAGIC			0x59544346	/* FCTY */
 38#define NVRAM_HEADER			0x48534C46	/* FLSH */
 39#define POT_MAGIC1			0x54544f50	/* POTT */
 40#define POT_MAGIC2			0x504f		/* OP */
 41#define ML_MAGIC1			0x39685a42
 42#define ML_MAGIC2			0x26594131
 43#define TRX_MAGIC			0x30524448
 44#define SHSQ_MAGIC			0x71736873	/* shsq (weird ZTE H218N endianness) */
 45#define UBI_EC_MAGIC			0x23494255	/* UBI# */
 46
 47struct trx_header {
 48	uint32_t magic;
 49	uint32_t length;
 50	uint32_t crc32;
 51	uint16_t flags;
 52	uint16_t version;
 53	uint32_t offset[3];
 54} __packed;
 55
 56static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
 57				 u64 offset, uint32_t mask_flags)
 58{
 59	part->name = name;
 60	part->offset = offset;
 61	part->mask_flags = mask_flags;
 62}
 63
 64static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
 65						  size_t offset)
 66{
 67	uint32_t buf;
 68	size_t bytes_read;
 69	int err;
 70
 71	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
 72			(uint8_t *)&buf);
 73	if (err && !mtd_is_bitflip(err)) {
 74		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
 75			offset, err);
 76		goto out_default;
 77	}
 78
 79	if (buf == UBI_EC_MAGIC)
 80		return "ubi";
 81
 82out_default:
 83	return "rootfs";
 84}
 85
 86static int bcm47xxpart_parse(struct mtd_info *master,
 87			     const struct mtd_partition **pparts,
 88			     struct mtd_part_parser_data *data)
 89{
 90	struct mtd_partition *parts;
 91	uint8_t i, curr_part = 0;
 92	uint32_t *buf;
 93	size_t bytes_read;
 94	uint32_t offset;
 95	uint32_t blocksize = master->erasesize;
 96	struct trx_header *trx;
 97	int trx_part = -1;
 98	int last_trx_part = -1;
 99	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
100	int err;
101
102	/*
103	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
104	 * partitions were aligned to at least 0x1000 anyway.
105	 */
106	if (blocksize < 0x1000)
107		blocksize = 0x1000;
108
109	/* Alloc */
110	parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
111			GFP_KERNEL);
112	if (!parts)
113		return -ENOMEM;
114
115	buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
116	if (!buf) {
117		kfree(parts);
118		return -ENOMEM;
119	}
120
121	/* Parse block by block looking for magics */
122	for (offset = 0; offset <= master->size - blocksize;
123	     offset += blocksize) {
124		/* Nothing more in higher memory on BCM47XX (MIPS) */
125		if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
126			break;
127
128		if (curr_part >= BCM47XXPART_MAX_PARTS) {
129			pr_warn("Reached maximum number of partitions, scanning stopped!\n");
130			break;
131		}
132
133		/* Read beginning of the block */
134		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
135			       &bytes_read, (uint8_t *)buf);
136		if (err && !mtd_is_bitflip(err)) {
137			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
138			       offset, err);
139			continue;
140		}
141
142		/* Magic or small NVRAM at 0x400 */
143		if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
144		    (buf[0x400 / 4] == NVRAM_HEADER)) {
145			bcm47xxpart_add_part(&parts[curr_part++], "boot",
146					     offset, MTD_WRITEABLE);
147			continue;
148		}
149
150		/*
151		 * board_data starts with board_id which differs across boards,
152		 * but we can use 'MPFR' (hopefully) magic at 0x100
153		 */
154		if (buf[0x100 / 4] == BOARD_DATA_MAGIC) {
155			bcm47xxpart_add_part(&parts[curr_part++], "board_data",
156					     offset, MTD_WRITEABLE);
157			continue;
158		}
159
160		/* Found on Huawei E970 */
161		if (buf[0x000 / 4] == FACTORY_MAGIC) {
162			bcm47xxpart_add_part(&parts[curr_part++], "factory",
163					     offset, MTD_WRITEABLE);
164			continue;
165		}
166
167		/* POT(TOP) */
168		if (buf[0x000 / 4] == POT_MAGIC1 &&
169		    (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
170			bcm47xxpart_add_part(&parts[curr_part++], "POT", offset,
171					     MTD_WRITEABLE);
172			continue;
173		}
174
175		/* ML */
176		if (buf[0x010 / 4] == ML_MAGIC1 &&
177		    buf[0x014 / 4] == ML_MAGIC2) {
178			bcm47xxpart_add_part(&parts[curr_part++], "ML", offset,
179					     MTD_WRITEABLE);
180			continue;
181		}
182
183		/* TRX */
184		if (buf[0x000 / 4] == TRX_MAGIC) {
185			if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
186				pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
187				break;
188			}
189
190			trx = (struct trx_header *)buf;
191
192			trx_part = curr_part;
193			bcm47xxpart_add_part(&parts[curr_part++], "firmware",
194					     offset, 0);
195
196			i = 0;
197			/* We have LZMA loader if offset[2] points to sth */
198			if (trx->offset[2]) {
199				bcm47xxpart_add_part(&parts[curr_part++],
200						     "loader",
201						     offset + trx->offset[i],
202						     0);
203				i++;
204			}
205
206			if (trx->offset[i]) {
207				bcm47xxpart_add_part(&parts[curr_part++],
208						     "linux",
209						     offset + trx->offset[i],
210						     0);
211				i++;
212			}
213
214			/*
215			 * Pure rootfs size is known and can be calculated as:
216			 * trx->length - trx->offset[i]. We don't fill it as
217			 * we want to have jffs2 (overlay) in the same mtd.
218			 */
219			if (trx->offset[i]) {
220				const char *name;
221
222				name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
223				bcm47xxpart_add_part(&parts[curr_part++],
224						     name,
225						     offset + trx->offset[i],
226						     0);
227				i++;
228			}
229
230			last_trx_part = curr_part - 1;
231
232			/*
233			 * We have whole TRX scanned, skip to the next part. Use
234			 * roundown (not roundup), as the loop will increase
235			 * offset in next step.
236			 */
237			offset = rounddown(offset + trx->length, blocksize);
238			continue;
239		}
240
241		/* Squashfs on devices not using TRX */
242		if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
243		    buf[0x000 / 4] == SHSQ_MAGIC) {
244			bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
245					     offset, 0);
246			continue;
247		}
248
249		/*
250		 * New (ARM?) devices may have NVRAM in some middle block. Last
251		 * block will be checked later, so skip it.
252		 */
253		if (offset != master->size - blocksize &&
254		    buf[0x000 / 4] == NVRAM_HEADER) {
255			bcm47xxpart_add_part(&parts[curr_part++], "nvram",
256					     offset, 0);
257			continue;
258		}
259
260		/* Read middle of the block */
261		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
262			       (uint8_t *)buf);
263		if (err && !mtd_is_bitflip(err)) {
264			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
265			       offset, err);
266			continue;
267		}
268
269		/* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
270		if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
271			bcm47xxpart_add_part(&parts[curr_part++], "board_data",
272					     offset, MTD_WRITEABLE);
273			continue;
274		}
275	}
276
277	/* Look for NVRAM at the end of the last block. */
278	for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) {
279		if (curr_part >= BCM47XXPART_MAX_PARTS) {
280			pr_warn("Reached maximum number of partitions, scanning stopped!\n");
281			break;
282		}
283
284		offset = master->size - possible_nvram_sizes[i];
285		err = mtd_read(master, offset, 0x4, &bytes_read,
286			       (uint8_t *)buf);
287		if (err && !mtd_is_bitflip(err)) {
288			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
289			       offset, err);
290			continue;
291		}
292
293		/* Standard NVRAM */
294		if (buf[0] == NVRAM_HEADER) {
295			bcm47xxpart_add_part(&parts[curr_part++], "nvram",
296					     master->size - blocksize, 0);
297			break;
298		}
299	}
300
301	kfree(buf);
302
303	/*
304	 * Assume that partitions end at the beginning of the one they are
305	 * followed by.
306	 */
307	for (i = 0; i < curr_part; i++) {
308		u64 next_part_offset = (i < curr_part - 1) ?
309				       parts[i + 1].offset : master->size;
310
311		parts[i].size = next_part_offset - parts[i].offset;
312		if (i == last_trx_part && trx_part >= 0)
313			parts[trx_part].size = next_part_offset -
314					       parts[trx_part].offset;
315	}
316
317	*pparts = parts;
318	return curr_part;
319};
320
321static struct mtd_part_parser bcm47xxpart_mtd_parser = {
322	.parse_fn = bcm47xxpart_parse,
323	.name = "bcm47xxpart",
324};
325module_mtd_part_parser(bcm47xxpart_mtd_parser);
326
327MODULE_LICENSE("GPL");
328MODULE_DESCRIPTION("MTD partitioning for BCM47XX flash memories");