nand-part.c 7.9 KB
Newer Older
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
/*
 * mbr.c
 * (C) Copyright 2012
 * Patrick H Wood, All rights reserved.
 * Heavily modified from the Allwinner file drivers/block/sun4i_nand/nfd/mbr.c.
 * (Allwinner copyright block retained below.)
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

/*
 * drivers/block/sun4i_nand/nfd/mbr.c
 * (C) Copyright 2007-2012
 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
52
#include <string.h>
53
#include <sys/ioctl.h>
54
#include <sys/mount.h> /* BLKRRPART */
55
56
57
58
59
60
#include "nand-common.h"

// so far, only known formats are for A10 and A20
#if defined(A10)
# include "nand-part-a10.h"
#elif defined(A20)
61
62
# include "nand-part-a20.h"
#endif
63
64
65

#define MAX_NAME 16

66
67
68
69
static void printmbrheader(MBR *mbr)
{
	printf("mbr: version 0x%08x, magic %8.8s\n", mbr->version, mbr->magic);
}
70

71
static MBR *_get_mbr(int fd, int mbr_num, int force)
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
{
	MBR *mbr;

	/*request mbr space*/
	mbr = malloc(sizeof(MBR));
	if(mbr == NULL)
	{
		printf("%s : request memory fail\n",__FUNCTION__);
		return NULL;
	}

	/*get mbr from nand device*/
	lseek(fd,MBR_START_ADDRESS + MBR_SIZE*mbr_num,SEEK_SET);
	if(read(fd,mbr,MBR_SIZE) == MBR_SIZE)
	{
		/*checksum*/
		printf("check partition table copy %d: ", mbr_num);
89
		printmbrheader(mbr);
90
91
92
93
94
95
		if (force) {
			strncpy((char *)mbr->magic, MBR_MAGIC, 8);
			mbr->version = MBR_VERSION;
			return mbr;
		}
		if(strncmp((char *)mbr->magic, MBR_MAGIC, 8))
96
		{
97
			printf("magic %8.8s is not %8s\n", mbr->magic, MBR_MAGIC);
98
99
			return NULL;
		}
100
		if(mbr->version != MBR_VERSION)
101
		{
102
			printf("version 0x%08x is not 0x%08x\n", mbr->version, MBR_VERSION);
103
104
			return NULL;
		}
105
106
107
108
109
110
111
112
113
114
		if(*(__u32 *)mbr == calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4))
		{
			printf("OK\n");
			return mbr;
		}
		printf("BAD!\n");
	}
	return NULL;
}

115
static __s32 _free_mbr(MBR *mbr)
116
117
118
119
120
121
122
123
124
125
{
	if(mbr)
	{
		free(mbr);
		mbr = 0;
	}

	return 0;
}

126
static void printmbr(MBR *mbr)
127
{
128
	unsigned int part_cnt;
129
130
	
	printmbrheader(mbr);
131
	printf("%d partitions\n", mbr->PartCount);
132
133
	for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
	{
134
135
136
137
138
139
140
		printf("partition %2d: class = %12s, name = %12s, partition start = %8d, partition size = %8d user_type=%d\n",
					part_cnt + 1,
					mbr->array[part_cnt].classname,
					mbr->array[part_cnt].name,
					mbr->array[part_cnt].addrlo,
					mbr->array[part_cnt].lenlo,
					mbr->array[part_cnt].user_type);
141
142
	}
}
143
int checkmbrs(int fd)
144
145
146
147
148
149
150
{
	int i;
	MBR *mbrs[MBR_COPY_NUM];
	MBR *mbr = NULL;

	memset((void *) mbrs, 0, sizeof(mbrs));
	for (i = 0; i < MBR_COPY_NUM; i++) {
151
		mbrs[i] = _get_mbr(fd, i, 0);
152
153
154
155
156
157
158
159
160
		if (mbrs[i])
			mbr = mbrs[i];
	}
	if (!mbr) {
		printf("all partition tables are bad!\n");
		for (i = 0; i < MBR_COPY_NUM; i++) {
			if (mbrs[i])
				_free_mbr(mbrs[i]);
		}
161
		return 0;
162
163
	}

164
	printmbr(mbr);
165
166
167
168
	for (i = 0; i < MBR_COPY_NUM; i++) {
		if (mbrs[i])
			_free_mbr(mbrs[i]);
	}
169
	return 1;
170
171
}

172
static int writembrs(int fd, char names[][MAX_NAME], __u32 start, __u32 *lens, unsigned int *user_types, int nparts, int partoffset, int force)
173
{
174
	unsigned int part_cnt = 0;
175
176
177
178
179
180
181
182
	int i;
	char yn = 'n';
	MBR *mbrs[MBR_COPY_NUM];
	MBR *mbr = NULL;
	FILE *backup;

	memset((void *) mbrs, 0, sizeof(mbrs));
	for (i = 0; i < MBR_COPY_NUM; i++) {
183
		mbrs[i] = _get_mbr(fd, i, force);
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
		if (mbrs[i])
			mbr = mbrs[i];
	}
	if (!mbr) {
		printf("all partition tables are bad!\n");
		for (i = 0; i < MBR_COPY_NUM; i++) {
			if (mbrs[i])
				_free_mbr(mbrs[i]);
		}
		return 0;
	}
	// back up mbr data
	backup = fopen("nand_mbr.backup", "w");
	if (!backup) {
		printf("can't open nand_mbr.backup to back up mbr data\n");
		for (i = 0; i < MBR_COPY_NUM; i++) {
			if (mbrs[i])
				_free_mbr(mbrs[i]);
		}
		return 0;
	}

206
207
	fprintf(backup, "%d ", mbr->array[0].addrlo);
	for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
208
	{
209
210
		fprintf(backup, "'%s %d %d' ", mbr->array[part_cnt].name,
		                  mbr->array[part_cnt].lenlo, mbr->array[part_cnt].user_type);
211
212
213
214
	}
	fprintf(backup, "\n");
	fclose(backup);

215
216
217
	mbr->PartCount = nparts + partoffset;
	if (partoffset)
		start = mbr->array[0].addrlo + mbr->array[0].lenlo;
218
	for(i = 0; i < nparts; i++) {
219
220
221
222
223
224
225
226
227
		strcpy((char *)mbr->array[i+partoffset].name, names[i]);
		strcpy((char *)mbr->array[i+partoffset].classname, "DISK");
		memset((void *) mbr->array[i+partoffset].res, 0, sizeof(mbr->array[i+partoffset].res));
		mbr->array[i+partoffset].user_type = user_types[i];
		mbr->array[i+partoffset].ro = 0;
		mbr->array[i+partoffset].addrhi = 0;
		mbr->array[i+partoffset].lenhi = 0;
		mbr->array[i+partoffset].addrlo = start;
		mbr->array[i+partoffset].lenlo = lens[i];
228
229
230
231
		start += lens[i];
	}

	printf("\nready to write new partition tables:\n");
232
	printmbr(mbr);
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
	for (i = 0; i < MBR_COPY_NUM; i++) {
		if (mbrs[i])
			_free_mbr(mbrs[i]);
	}
	printf("\nwrite new partition tables? (Y/N)\n");
	read(0, &yn, 1);
	if (yn != 'Y' && yn != 'y') {
		printf("aborting\n");
		return 0;
	}

	for (i = 0; i < MBR_COPY_NUM; i++) {
		mbr->index = i;
		// calculate new checksum
		*(__u32 *)mbr = calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4);
		lseek(fd,MBR_START_ADDRESS + MBR_SIZE*i,SEEK_SET);
		write(fd,mbr,MBR_SIZE);
	}
251
252
253
254

	if (ioctl(fd, BLKRRPART, NULL))
		perror("Failed rereading partition table");

255
256
257
	return 1;
}

258
int nand_part (int argc, char **argv, const char *cmd, int fd, int force)
259
260
{
	int partoffset = 0;
261
262
263
	int i;
	char names[MAX_PART_COUNT][MAX_NAME];
	__u32 lens[MAX_PART_COUNT];
264
	unsigned int user_types[MAX_PART_COUNT];
265
	__u32 start;
266
267
268


	// parse name/len arguments
269
	memset((void *) user_types, 0, sizeof(user_types));
270
	if (argc > 0) {
271
		if (sscanf(argv[0], "%u", &start) != 1) {
272
273
274
275
276
277
278
279
280
281
282
			partoffset++;
			if (force) {
				printf("if using -f, must set info for first partition\n");
				usage(cmd);
				close(fd);
				return -3;
			}
		}
		else {
			argc--;
			argv++;
283
		}
284
285
286
287
288
289
290

		if (start < MBR_SIZE * MBR_COPY_NUM / 512) {
			printf("Partition 1 starting offset must be at least %d\n", MBR_SIZE * MBR_COPY_NUM / 512);
			close(fd);
			return -3;
		}

291
		for (i = 0; i < argc; i++) {
292
			if (sscanf(argv[i], "%s %d %d", names[i], &lens[i], &user_types[i]) < 2) {
293
				printf("bad 'name len' argument\n");
294
				usage(cmd);
295
296
297
298
299
300
301
302
				close(fd);
				return -3;
			}
		}
	}

	checkmbrs(fd);

303
	if (argc > MAX_PART_COUNT - partoffset) {
304
		printf("too many partitions specified (MAX 14)\n");
305
		usage(cmd);
306
307
308
309
310
311
		close(fd);
		return -2;
	}


	if (argc > 0) {
312
		if (writembrs(fd, names, start, lens, user_types, argc, partoffset, force)) {
313
314
			printf("\nverifying new partition tables:\n");
			checkmbrs(fd);
315
			printf("rereading partition table... returned %d\n", ioctl(fd, BLKRRPART, 0));
316
317
318
319
320
321
		}
	}
	close(fd);

	return 0;
}