summaryrefslogtreecommitdiffstats
path: root/commands/ubiformat.c
blob: a88672d6c229523ad06ebe582a64de82154755be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
 * Copyright (C) 2008 Nokia Corporation
 * Copyright (C) 2012 Wolfram Sang, Pengutronix
 *
 * 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 program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details.
 */

/*
 * An utility to format MTD devices into UBI and flash UBI images.
 *
 * Author: Artem Bityutskiy
 */

/*
 * Maximum amount of consequtive eraseblocks which are considered as normal by
 * this utility. Otherwise it is assume that something is wrong with the flash
 * or the driver, and eraseblocks are stopped being marked as bad.
 */
#define MAX_CONSECUTIVE_BAD_BLOCKS 4

#define PROGRAM_NAME	"ubiformat"

#include <common.h>
#include <command.h>
#include <fs.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#include <crc.h>
#include <stdlib.h>
#include <clock.h>
#include <malloc.h>
#include <ioctl.h>
#include <libbb.h>
#include <libfile.h>
#include <ubiformat.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/ubi.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/log2.h>
#include <linux/mtd/mtd-abi.h>
#include <mtd/libscan.h>
#include <mtd/libubigen.h>
#include <mtd/ubi-user.h>
#include <mtd/utils.h>
#include <mtd/ubi-media.h>
#include <mtd/mtd-peb.h>

static int parse_opt(int argc, char *argv[], struct ubiformat_args *args,
		     char **node)
{
	srand(get_time_ns());
	memset(args, 0, sizeof(*args));

	while (1) {
		int key;
		unsigned long int image_seq;

		key = getopt(argc, argv, "nyqve:x:s:O:f:S:Q:");
		if (key == -1)
			break;

		switch (key) {
		case 's':
			args->subpage_size = strtoull_suffix(optarg, NULL, 0);
			if (args->subpage_size <= 0)
				return errmsg("bad sub-page size: \"%s\"", optarg);
			if (!is_power_of_2(args->subpage_size))
				return errmsg("sub-page size should be power of 2");
			break;

		case 'O':
			args->vid_hdr_offs = simple_strtoul(optarg, NULL, 0);
			if (args->vid_hdr_offs <= 0)
				return errmsg("bad VID header offset: \"%s\"", optarg);
			break;

		case 'e':
			args->ec = simple_strtoull(optarg, NULL, 0);
			if (args->ec < 0)
				return errmsg("bad erase counter value: \"%s\"", optarg);
			if (args->ec >= EC_MAX)
				return errmsg("too high erase %llu, counter, max is %u", args->ec, EC_MAX);
			args->override_ec = 1;
			break;

		case 'f':
			args->image = optarg;
			break;

		case 'n':
			args->novtbl = 1;
			break;

		case 'y':
			args->yes = 1;
			break;

		case 'q':
			args->quiet = 1;
			break;

		case 'x':
			args->ubi_ver = simple_strtoul(optarg, NULL, 0);
			if (args->ubi_ver < 0)
				return errmsg("bad UBI version: \"%s\"", optarg);
			break;

		case 'Q':
			image_seq = simple_strtoul(optarg, NULL, 0);
			if (image_seq > 0xFFFFFFFF)
				return errmsg("bad UBI image sequence number: \"%s\"", optarg);
			args->image_seq = image_seq;
			break;

		case 'v':
			args->verbose = 1;
			break;

		default:
			return COMMAND_ERROR_USAGE;
		}
	}

	if (args->quiet && args->verbose)
		return errmsg("using \"-q\" and \"-v\" at the same time does not make sense");

	if (optind == argc)
		return errmsg("MTD device name was not specified");
	else if (optind != argc - 1)
		return errmsg("more then one MTD device specified");

	if (args->image && args->novtbl)
		return errmsg("-n cannot be used together with -f");


	*node = argv[optind];

	return 0;
}

static int do_ubiformat(int argc, char *argv[])
{
	int err, fd;
	struct ubiformat_args args;
	char *node = NULL;
	struct mtd_info_user mtd_user;

	err = parse_opt(argc, argv, &args, &node);
	if (err)
		return err;

	fd = open(node, O_RDWR);
	if (fd < 0)
		return sys_errmsg("cannot open \"%s\"", node);

	err = ioctl(fd, MEMGETINFO, &mtd_user);
	if (err) {
		sys_errmsg("MEMGETINFO ioctl request failed");
		goto out_close;
	}

	err = ubiformat(mtd_user.mtd, &args);

out_close:
	close(fd);

	return err;
}

BAREBOX_CMD_HELP_START(ubiformat)
BAREBOX_CMD_HELP_TEXT("A tool to format MTD devices and flash UBI images")
BAREBOX_CMD_HELP_TEXT("")
BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT("-s BYTES", "minimum input/output unit used for UBI headers")
BAREBOX_CMD_HELP_OPT("\t", "e.g. sub-page size in case of NAND flash")
BAREBOX_CMD_HELP_OPT("-O OFFS\t", "offset if the VID header from start of the")
BAREBOX_CMD_HELP_OPT("\t", "physical eraseblock (default is the next minimum I/O unit or")
BAREBOX_CMD_HELP_OPT("\t", "sub-page after the EC header)")
BAREBOX_CMD_HELP_OPT("-n\t", "only erase all eraseblock and preserve erase")
BAREBOX_CMD_HELP_OPT("\t", "counters, do not write empty volume table")
BAREBOX_CMD_HELP_OPT("-f FILE\t", "flash image file")
BAREBOX_CMD_HELP_OPT("-e VALUE", "use VALUE as erase counter value for all eraseblocks")
BAREBOX_CMD_HELP_OPT("-x NUM\t", "UBI version number to put to EC headers (default 1)")
BAREBOX_CMD_HELP_OPT("-Q NUM\t", "32-bit UBI image sequence number to use")
BAREBOX_CMD_HELP_OPT("-y\t", "Assume yes for all questions")
BAREBOX_CMD_HELP_OPT("-q\t", "suppress progress percentage information")
BAREBOX_CMD_HELP_OPT("-v\t", "be verbose")
BAREBOX_CMD_HELP_TEXT("")
BAREBOX_CMD_HELP_TEXT("Example 1: ubiformat /dev/nand0 -y - format nand0 and assume yes")
BAREBOX_CMD_HELP_TEXT("Example 2: ubiformat /dev/nand0 -q -e 0 - format nand0,")
BAREBOX_CMD_HELP_TEXT("\tbe quiet and force erase counter value 0.")
BAREBOX_CMD_HELP_END

BAREBOX_CMD_START(ubiformat)
	.cmd		= do_ubiformat,
	BAREBOX_CMD_DESC("format an ubi volume")
	BAREBOX_CMD_OPTS("[-sOnfexQqv] MTDEVICE")
	BAREBOX_CMD_GROUP(CMD_GRP_PART)
	BAREBOX_CMD_HELP(cmd_ubiformat_help)
BAREBOX_CMD_END