diff options
| author | Dongsheng Yang <yangds.fnst@cn.fujitsu.com> | 2015-10-31 11:12:01 +0800 | 
|---|---|---|
| committer | Brian Norris <computersforpeace@gmail.com> | 2015-11-11 14:38:40 -0800 | 
| commit | 7d81790ced345585b1e647ca9d0f6678e7062fa4 (patch) | |
| tree | 02f61270c7a0fff7bb6b2e28f247a3d2fd6ff490 /nor-utils | |
| parent | 344753f2aacb94d98ce238f81fc4a4b6ef6adea9 (diff) | |
mtd-utils: Restructure the mtd-utils source.
* There is no code modification in this commit, only moving
* the files to proper place.
The user tools looks a little messy as we place almost
the all tools in the root directory of mtd-utils. To make
it more clear, I propose to introduce the following structure
for our source code.
mtd-utils/
	|-- lib
	|-- include
	|-- misc-utils
	|-- jffsX-utils
	|-- nand-utils
	|-- nor-utils
	|-- ubi-utils
	|-- ubifs-utils
	`-- tests
Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'nor-utils')
| -rw-r--r-- | nor-utils/rfddump.c | 337 | ||||
| -rw-r--r-- | nor-utils/rfdformat.c | 160 | 
2 files changed, 497 insertions, 0 deletions
diff --git a/nor-utils/rfddump.c b/nor-utils/rfddump.c new file mode 100644 index 0000000..0375bac --- /dev/null +++ b/nor-utils/rfddump.c @@ -0,0 +1,337 @@ +/* + * rfddump.c + * + * Copyright (C) 2005 Sean Young <sean@mess.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + */ + +#define PROGRAM_NAME "rfddump" +#define VERSION "$Revision 1.0 $" + +#define _XOPEN_SOURCE 500 /* For pread */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <getopt.h> + +#include <mtd/mtd-user.h> +#include <linux/types.h> +#include <mtd_swab.h> + +/* next is an array of mapping for each corresponding sector */ +#define RFD_MAGIC		0x9193 +#define HEADER_MAP_OFFSET       3 +#define SECTOR_DELETED          0x0000 +#define SECTOR_ZERO             0xfffe +#define SECTOR_FREE             0xffff + +#define SECTOR_SIZE             512 + +#define SECTORS_PER_TRACK	63 + + +struct rfd { +	int block_size; +	int block_count; +	int header_sectors; +	int data_sectors; +	int header_size; +	uint16_t *header; +	int sector_count; +	int *sector_map; +	const char *mtd_filename; +	const char *out_filename; +	int verbose; +}; + +void display_help(void) +{ +	printf("Usage: %s [OPTIONS] MTD-device filename\n" +			"Dumps the contents of a resident flash disk\n" +			"\n" +			"-h         --help               display this help and exit\n" +			"-V         --version            output version information and exit\n" +			"-v         --verbose		Be verbose\n" +			"-b size    --blocksize          Block size (defaults to erase unit)\n", +			PROGRAM_NAME); +	exit(0); +} + +void display_version(void) +{ +	printf("%s " VERSION "\n" +			"\n" +			"This is free software; see the source for copying conditions.  There is NO\n" +			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", +			PROGRAM_NAME); + +	exit(0); +} + +void process_options(int argc, char *argv[], struct rfd *rfd) +{ +	int error = 0; + +	rfd->block_size = 0; +	rfd->verbose = 0; + +	for (;;) { +		int option_index = 0; +		static const char *short_options = "hvVb:"; +		static const struct option long_options[] = { +			{ "help", no_argument, 0, 'h' }, +			{ "version", no_argument, 0, 'V', }, +			{ "blocksize", required_argument, 0, 'b' }, +			{ "verbose", no_argument, 0, 'v' }, +			{ NULL, 0, 0, 0 } +		}; + +		int c = getopt_long(argc, argv, short_options, +				long_options, &option_index); +		if (c == EOF) +			break; + +		switch (c) { +			case 'h': +				display_help(); +				break; +			case 'V': +				display_version(); +				break; +			case 'v': +				rfd->verbose = 1; +				break; +			case 'b': +				rfd->block_size = atoi(optarg); +				break; +			case '?': +				error = 1; +				break; +		} +	} + +	if ((argc - optind) != 2 || error) +		display_help(); + +	rfd->mtd_filename = argv[optind]; +	rfd->out_filename = argv[optind + 1]; +} + +int build_block_map(struct rfd *rfd, int fd, int block) +{ +	int  i; +	int sectors; + +	if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size) +			!= rfd->header_size) { +		return -1; +	} + +	if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) { +		if (rfd->verbose) +			printf("Block #%02d: Magic missing\n", block); + +		return 0; +	} + +	sectors =  0; +	for (i=0; i<rfd->data_sectors; i++) { +		uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]); + +		if (entry == SECTOR_FREE || entry == SECTOR_DELETED) +			continue; + +		if (entry == SECTOR_ZERO) +			entry = 0; + +		if (entry >= rfd->sector_count) { +			fprintf(stderr, "%s: warning: sector %d out of range\n", +					rfd->mtd_filename, entry); +			continue; +		} + +		if (rfd->sector_map[entry] != -1) { +			fprintf(stderr, "%s: warning: more than one entry " +					"for sector %d\n", rfd->mtd_filename, entry); +			continue; +		} + +		rfd->sector_map[entry] = rfd->block_size * block + +			(i + rfd->header_sectors) * SECTOR_SIZE; +		sectors++; +	} + +	if (rfd->verbose) +		printf("Block #%02d: %d sectors\n", block, sectors); + +	return 1; +} + +int main(int argc, char *argv[]) +{ +	int fd, sectors_per_block; +	mtd_info_t mtd_info; +	struct rfd rfd; +	int i, blocks_found; +	int out_fd = 0; +	uint8_t sector[512]; +	int blank, rc, cylinders; + +	process_options(argc, argv, &rfd); + +	fd = open(rfd.mtd_filename, O_RDONLY); +	if (fd == -1) { +		perror(rfd.mtd_filename); +		return 1; +	} + +	if (rfd.block_size == 0) { +		if (ioctl(fd, MEMGETINFO, &mtd_info)) { +			perror(rfd.mtd_filename); +			close(fd); +			return 1; +		} + +		if (mtd_info.type != MTD_NORFLASH) { +			fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename); +			close(fd); +			return 2; +		} + +		sectors_per_block = mtd_info.erasesize / SECTOR_SIZE; + +		rfd.block_size = mtd_info.erasesize; +		rfd.block_count = mtd_info.size / mtd_info.erasesize; +	} else { +		struct stat st; + +		if (fstat(fd, &st) == -1) { +			perror(rfd.mtd_filename); +			close(fd); +			return 1; +		} + +		if (st.st_size % SECTOR_SIZE) +			fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename); + +		sectors_per_block = rfd.block_size / SECTOR_SIZE; + +		if (st.st_size % rfd.block_size) +			fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename); + +		rfd.block_count = st.st_size / rfd.block_size; + +		if (!rfd.block_count) { +			fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename); +			close(fd); +			return 2; +		} +	} + +	rfd.header_sectors = +		((HEADER_MAP_OFFSET + sectors_per_block) * +		 sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE; +	rfd.data_sectors = sectors_per_block - rfd.header_sectors; +	cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1) +		/ SECTORS_PER_TRACK; +	rfd.sector_count = cylinders * SECTORS_PER_TRACK; +	rfd.header_size = +		(HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t); + +	rfd.header = malloc(rfd.header_size); +	if (!rfd.header) { +		perror(PROGRAM_NAME); +		close(fd); +		return 2; +	} +	rfd.sector_map = malloc(rfd.sector_count * sizeof(int)); +	if (!rfd.sector_map) { +		perror(PROGRAM_NAME); +		close(fd); +		free(rfd.sector_map); +		return 2; +	} + +	rfd.mtd_filename = rfd.mtd_filename; + +	for (i=0; i<rfd.sector_count; i++) +		rfd.sector_map[i] = -1; + +	for (blocks_found=i=0; i<rfd.block_count; i++) { +		rc = build_block_map(&rfd, fd, i); +		if (rc > 0) +			blocks_found++; +		if (rc < 0) +			goto err; +	} + +	if (!blocks_found) { +		fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename); +		goto err; +	} + +	for (i=0; i<rfd.sector_count; i++) { +		if (rfd.sector_map[i] != -1) +			break; +	} + +	if (i == rfd.sector_count) { +		fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename); +		goto err; +	} + +	out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666); +	if (out_fd == -1) { +		perror(rfd.out_filename); +		goto err; +	} + +	blank = 0; +	for (i=0; i<rfd.sector_count; i++) { +		if (rfd.sector_map[i] == -1) { +			memset(sector, 0, SECTOR_SIZE); +			blank++; +		} else { +			if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i]) +					!= SECTOR_SIZE) { +				perror(rfd.mtd_filename); +				goto err; +			} +		} + +		if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) { +			perror(rfd.out_filename); +			goto err; +		} +	} + +	if (rfd.verbose) +		printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank); + +	close(out_fd); +	close(fd); +	free(rfd.header); +	free(rfd.sector_map); + +	return 0; + +err: +	if (out_fd) +		close(out_fd); + +	close(fd); +	free(rfd.header); +	free(rfd.sector_map); + +	return 2; +} diff --git a/nor-utils/rfdformat.c b/nor-utils/rfdformat.c new file mode 100644 index 0000000..17d9d2d --- /dev/null +++ b/nor-utils/rfdformat.c @@ -0,0 +1,160 @@ +/* + * rfdformat.c + * + * Copyright (C) 2005 Sean Young <sean@mess.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is very easy: just erase all the blocks and put the magic at + * the beginning of each block. + */ + +#define PROGRAM_NAME "rfdformat" +#define VERSION "$Revision 1.0 $" + +#define _XOPEN_SOURCE 500 /* For pread/pwrite */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <getopt.h> + +#include <mtd/mtd-user.h> +#include <linux/types.h> + +void display_help(void) +{ +	printf("Usage: %s [OPTIONS] MTD-device\n" +			"Formats NOR flash for resident flash disk\n" +			"\n" +			"-h         --help               display this help and exit\n" +			"-V         --version            output version information and exit\n", +			PROGRAM_NAME); +	exit(0); +} + +void display_version(void) +{ +	printf("%s " VERSION "\n" +			"\n" +			"This is free software; see the source for copying conditions.  There is NO\n" +			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", +			PROGRAM_NAME); + +	exit(0); +} + +void process_options(int argc, char *argv[], const char **mtd_filename) +{ +	int error = 0; + +	for (;;) { +		int option_index = 0; +		static const char *short_options = "hV"; +		static const struct option long_options[] = { +			{ "help", no_argument, 0, 'h' }, +			{ "version", no_argument, 0, 'V', }, +			{ NULL, 0, 0, 0 } +		}; + +		int c = getopt_long(argc, argv, short_options, +				long_options, &option_index); +		if (c == EOF) +			break; + +		switch (c) { +			case 'h': +				display_help(); +				break; +			case 'V': +				display_version(); +				break; +			case '?': +				error = 1; +				break; +		} +	} + +	if ((argc - optind) != 1 || error) +		display_help(); + +	*mtd_filename = argv[optind]; +} + +int main(int argc, char *argv[]) +{ +	static const uint8_t magic[] = { 0x93, 0x91 }; +	int fd, block_count, i; +	struct mtd_info_user mtd_info; +	char buf[512]; +	const char *mtd_filename; + +	process_options(argc, argv, &mtd_filename); + +	fd = open(mtd_filename, O_RDWR); +	if (fd == -1) { +		perror(mtd_filename); +		return 1; +	} + +	if (ioctl(fd, MEMGETINFO, &mtd_info)) { +		perror(mtd_filename); +		close(fd); +		return 1; +	} + +	if (mtd_info.type != MTD_NORFLASH) { +		fprintf(stderr, "%s: not NOR flash\n", mtd_filename); +		close(fd); +		return 2; +	} + +	if (mtd_info.size > 32*1024*1024) { +		fprintf(stderr, "%s: flash larger than 32MiB not supported\n", +				mtd_filename); +		close(fd); +		return 2; +	} + +	block_count = mtd_info.size / mtd_info.erasesize; + +	if (block_count < 2) { +		fprintf(stderr, "%s: at least two erase units required\n", +				mtd_filename); +		close(fd); +		return 2; +	} + +	for (i=0; i<block_count; i++) { +		struct erase_info_user erase_info; + +		erase_info.start = i * mtd_info.erasesize; +		erase_info.length = mtd_info.erasesize; + +		if (ioctl(fd, MEMERASE, &erase_info) != 0) { +			snprintf(buf, sizeof(buf), "%s: erase", mtd_filename); +			perror(buf); +			close(fd); +			return 2; +		} + +		if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize) +				!= sizeof(magic)) { +			snprintf(buf, sizeof(buf), "%s: write", mtd_filename); +			perror(buf); +			close(fd); +			return 2; +		} +	} + +	close(fd); + +	return 0; +}  | 
