nand-part.c 9.08 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
#ifdef A20
# include "nand-part-a20.h"
#else
# include "nand-part.h"
#endif
60
61
62

#define MAX_NAME 16

63
64
65
66
static void printmbrheader(MBR *mbr)
{
	printf("mbr: version 0x%08x, magic %8.8s\n", mbr->version, mbr->magic);
}
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
typedef struct tag_CRC32_DATA
{
	__u32 CRC;				//int的大小是32位
	__u32 CRC_32_Tbl[256];	//用来保存码表
}CRC32_DATA_t;

__u32 calc_crc32(void * buffer, __u32 length)
{
	__u32 i, j;
	CRC32_DATA_t crc32;		//
	__u32 CRC32 = 0xffffffff; //设置初始值
	crc32.CRC = 0;

	for( i = 0; i < 256; ++i)//用++i以提高效率
	{
		crc32.CRC = i;
		for( j = 0; j < 8 ; ++j)
		{
			//这个循环实际上就是用"计算法"来求取CRC的校验码
			if(crc32.CRC & 1)
				crc32.CRC = (crc32.CRC >> 1) ^ 0xEDB88320;
			else //0xEDB88320就是CRC-32多项表达式的值
				crc32.CRC >>= 1;
		}
		crc32.CRC_32_Tbl[i] = crc32.CRC;
	}

	CRC32 = 0xffffffff; //设置初始值
	for( i = 0; i < length; ++i)
	{
		CRC32 = crc32.CRC_32_Tbl[(CRC32^((unsigned char*)buffer)[i]) & 0xff] ^ (CRC32>>8);
	}
	//return CRC32;
	return CRC32^0xffffffff;
}

104
MBR *_get_mbr(int fd, int mbr_num, int force)
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
{
	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);
122
		printmbrheader(mbr);
123
124
125
126
127
128
129
130
		if (force) {
			strncpy((char *)mbr->magic, MBR_MAGIC, 8);
#ifdef MBR_VERSION
			mbr->version = MBR_VERSION;
#endif
			return mbr;
		}
		if(strncmp((char *)mbr->magic, MBR_MAGIC, 8))
131
		{
132
			printf("magic %8.8s is not %8s\n", mbr->magic, MBR_MAGIC);
133
134
			return NULL;
		}
135
136
#ifdef MBR_VERSION
		if(mbr->version != MBR_VERSION)
137
		{
138
			printf("version 0x%08x is not 0x%08x\n", mbr->version, MBR_VERSION);
139
140
			return NULL;
		}
141
#endif
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
		if(*(__u32 *)mbr == calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4))
		{
			printf("OK\n");
			return mbr;
		}
		printf("BAD!\n");
	}
	return NULL;
}

__s32 _free_mbr(MBR *mbr)
{
	if(mbr)
	{
		free(mbr);
		mbr = 0;
	}

	return 0;
}

163
164
void printmbr(MBR *mbr)
{
165
	unsigned int part_cnt;
166
167
	
	printmbrheader(mbr);
168
169
	for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
	{
170
171
172
173
174
175
176
		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);
177
178
	}
}
179
180
void checkmbrs(int fd)
{
181
	unsigned int part_cnt = 0;
182
183
184
185
186
187
	int i;
	MBR *mbrs[MBR_COPY_NUM];
	MBR *mbr = NULL;

	memset((void *) mbrs, 0, sizeof(mbrs));
	for (i = 0; i < MBR_COPY_NUM; i++) {
188
		mbrs[i] = _get_mbr(fd, i, 0);
189
190
191
192
193
194
195
196
197
198
199
200
		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;
	}

201
	printmbr(mbr);
202
203
204
205
206
207
208
	for (i = 0; i < MBR_COPY_NUM; i++) {
		if (mbrs[i])
			_free_mbr(mbrs[i]);
	}
	printf("%d partitions\n", part_cnt);
}

209
int writembrs(int fd, char names[][MAX_NAME], __u32 start, __u32 *lens, unsigned int *user_types, int nparts, int partoffset, int force)
210
{
211
	unsigned int part_cnt = 0;
212
213
214
215
216
217
218
219
	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++) {
220
		mbrs[i] = _get_mbr(fd, i, force);
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
		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;
	}

243
244
	fprintf(backup, "%d ", mbr->array[0].addrlo);
	for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
245
	{
246
247
		fprintf(backup, "'%s %d %d' ", mbr->array[part_cnt].name,
		                  mbr->array[part_cnt].lenlo, mbr->array[part_cnt].user_type);
248
249
250
251
	}
	fprintf(backup, "\n");
	fclose(backup);

252
253
254
	mbr->PartCount = nparts + partoffset;
	if (partoffset)
		start = mbr->array[0].addrlo + mbr->array[0].lenlo;
255
	for(i = 0; i < nparts; i++) {
256
257
258
259
260
261
262
263
264
		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];
265
266
267
268
		start += lens[i];
	}

	printf("\nready to write new partition tables:\n");
269
	printmbr(mbr);
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
	for (i = 0; i < MBR_COPY_NUM; i++) {
		if (mbrs[i])
			_free_mbr(mbrs[i]);
	}
	printf("%d partitions\n", part_cnt);
	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);
	}
289
290
291
292

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

293
294
295
	return 1;
}

296
297
298
299
300
301
void usage(const char *cmd)
{
	printf("usage: %s nand-device 'name2 len2 [usertype2]' ['name3 len3 [usertype3]'] ...\n", cmd);
	printf("or     %s nand-device [-f] start1 'name1 len1 [usertype1]' ['name2 len2 [usertype2]'] ...\n", cmd);
}

302
303
304
int main (int argc, char **argv)
{
	int fd;
305
	int force = 0;		// force write even if magics and CRCs don't match
306
	int partoffset = 0;
307
308
309
310
311
	int i;
	char *nand = "/dev/nand";
	char *cmd = argv[0];
	char names[MAX_PART_COUNT][MAX_NAME];
	__u32 lens[MAX_PART_COUNT];
312
	unsigned int user_types[MAX_PART_COUNT];
313
	__u32 start;
314
315
316
317

	argc--;
	argv++;

318
319
320
321
322
323
324
325
	if (argc > 0) {
		if (!strcmp(argv[0], "-f")) {
			force++;
			argc--;
			argv++;
		}
	}

326
327
328
329
330
331
332
	if (argc > 0) {
		nand = argv[0];
		argc--;
		argv++;
	}
	fd = open(nand, O_RDWR);
	if (fd < 0) {
333
		usage(cmd);
334
335
336
337
		return -1;
	}

	// parse name/len arguments
338
	memset((void *) user_types, 0, sizeof(user_types));
339
	if (argc > 0) {
340
		if (sscanf(argv[0], "%u", &start) != 1) {
341
342
343
344
345
346
347
348
349
350
351
			partoffset++;
			if (force) {
				printf("if using -f, must set info for first partition\n");
				usage(cmd);
				close(fd);
				return -3;
			}
		}
		else {
			argc--;
			argv++;
352
		}
353
		for (i = 0; i < argc; i++) {
354
			if (sscanf(argv[i], "%s %d %d", names[i], &lens[i], &user_types[i]) < 2) {
355
				printf("bad 'name len' argument\n");
356
				usage(cmd);
357
358
359
360
361
362
363
364
				close(fd);
				return -3;
			}
		}
	}

	checkmbrs(fd);

365
	if (argc > MAX_PART_COUNT - partoffset) {
366
		printf("too many partitions specified (MAX 14)\n");
367
		usage(cmd);
368
369
370
371
372
373
		close(fd);
		return -2;
	}


	if (argc > 0) {
374
		if (writembrs(fd, names, start, lens, user_types, argc, partoffset, force)) {
375
376
			printf("\nverifying new partition tables:\n");
			checkmbrs(fd);
377
			printf("rereading partition table... returned %d\n", ioctl(fd, BLKRRPART, 0));
378
379
380
381
382
383
		}
	}
	close(fd);

	return 0;
}