1 /*
2 * mbr.c
3 * (C) Copyright 2012
4 * Patrick H Wood, All rights reserved.
5 * Heavily modified from the Allwinner file drivers/block/sun4i_nand/nfd/mbr.c.
6 * (Allwinner copyright block retained below.)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 */
24
25 /*
26 * drivers/block/sun4i_nand/nfd/mbr.c
27 * (C) Copyright 2007-2012
28 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
29 *
30 * This program is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU General Public License as
32 * published by the Free Software Foundation; either version 2 of
33 * the License, or (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
43 * MA 02111-1307 USA
44 */
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <string.h>
53 #ifdef __linux__
54 # include <sys/ioctl.h>
55 # include <sys/mount.h> /* BLKRRPART */
56 #endif
57 #include "nand-common.h"
58
59 // so far, only known formats are for A10 and A20
60 #if defined(A10)
61 # include "nand-part-a10.h"
62 #elif defined(A20)
63 # include "nand-part-a20.h"
64 #endif
65
66 #define MAX_NAME 16
67
printmbrheader(MBR * mbr)68 static void printmbrheader(MBR *mbr)
69 {
70 printf("mbr: version 0x%08x, magic %8.8s\n", mbr->version, mbr->magic);
71 }
72
_get_mbr(int fd,int mbr_num,int force)73 static MBR *_get_mbr(int fd, int mbr_num, int force)
74 {
75 MBR *mbr;
76
77 /*request mbr space*/
78 mbr = malloc(sizeof(MBR));
79 if(mbr == NULL)
80 {
81 printf("%s : request memory fail\n",__FUNCTION__);
82 return NULL;
83 }
84
85 /*get mbr from nand device*/
86 lseek(fd,MBR_START_ADDRESS + MBR_SIZE*mbr_num,SEEK_SET);
87 if(read(fd,mbr,MBR_SIZE) == MBR_SIZE)
88 {
89 /*checksum*/
90 printf("check partition table copy %d: ", mbr_num);
91 printmbrheader(mbr);
92 if (force) {
93 strncpy((char *)mbr->magic, MBR_MAGIC, 8);
94 mbr->version = MBR_VERSION;
95 return mbr;
96 }
97 if(strncmp((char *)mbr->magic, MBR_MAGIC, 8))
98 {
99 printf("magic %8.8s is not %8s\n", mbr->magic, MBR_MAGIC);
100 return NULL;
101 }
102 if(mbr->version != MBR_VERSION)
103 {
104 printf("version 0x%08x is not 0x%08x\n", mbr->version, MBR_VERSION);
105 return NULL;
106 }
107 if(*(__u32 *)mbr == calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4))
108 {
109 printf("OK\n");
110 return mbr;
111 }
112 printf("BAD!\n");
113 }
114 return NULL;
115 }
116
_free_mbr(MBR * mbr)117 static __s32 _free_mbr(MBR *mbr)
118 {
119 if(mbr)
120 {
121 free(mbr);
122 mbr = 0;
123 }
124
125 return 0;
126 }
127
printmbr(MBR * mbr)128 static void printmbr(MBR *mbr)
129 {
130 unsigned int part_cnt;
131
132 printmbrheader(mbr);
133 printf("%d partitions\n", mbr->PartCount);
134 for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
135 {
136 printf("partition %2d: class = %12s, name = %12s, partition start = %8d, partition size = %8d user_type=%d\n",
137 part_cnt + 1,
138 mbr->array[part_cnt].classname,
139 mbr->array[part_cnt].name,
140 mbr->array[part_cnt].addrlo,
141 mbr->array[part_cnt].lenlo,
142 mbr->array[part_cnt].user_type);
143 }
144 }
checkmbrs(int fd)145 int checkmbrs(int fd)
146 {
147 int i;
148 MBR *mbrs[MBR_COPY_NUM];
149 MBR *mbr = NULL;
150
151 memset((void *) mbrs, 0, sizeof(mbrs));
152 for (i = 0; i < MBR_COPY_NUM; i++) {
153 mbrs[i] = _get_mbr(fd, i, 0);
154 if (mbrs[i])
155 mbr = mbrs[i];
156 }
157 if (!mbr) {
158 printf("all partition tables are bad!\n");
159 for (i = 0; i < MBR_COPY_NUM; i++) {
160 if (mbrs[i])
161 _free_mbr(mbrs[i]);
162 }
163 return 0;
164 }
165
166 printmbr(mbr);
167 for (i = 0; i < MBR_COPY_NUM; i++) {
168 if (mbrs[i])
169 _free_mbr(mbrs[i]);
170 }
171 return 1;
172 }
173
writembrs(int fd,char names[][MAX_NAME],__u32 start,__u32 * lens,unsigned int * user_types,int nparts,int partoffset,int force)174 static int writembrs(int fd, char names[][MAX_NAME], __u32 start, __u32 *lens, unsigned int *user_types, int nparts, int partoffset, int force)
175 {
176 unsigned int part_cnt = 0;
177 int i;
178 char yn = 'n';
179 MBR *mbrs[MBR_COPY_NUM];
180 MBR *mbr = NULL;
181 FILE *backup;
182
183 memset((void *) mbrs, 0, sizeof(mbrs));
184 for (i = 0; i < MBR_COPY_NUM; i++) {
185 mbrs[i] = _get_mbr(fd, i, force);
186 if (mbrs[i])
187 mbr = mbrs[i];
188 }
189 if (!mbr) {
190 printf("all partition tables are bad!\n");
191 for (i = 0; i < MBR_COPY_NUM; i++) {
192 if (mbrs[i])
193 _free_mbr(mbrs[i]);
194 }
195 return 0;
196 }
197 // back up mbr data
198 backup = fopen("nand_mbr.backup", "w");
199 if (!backup) {
200 printf("can't open nand_mbr.backup to back up mbr data\n");
201 for (i = 0; i < MBR_COPY_NUM; i++) {
202 if (mbrs[i])
203 _free_mbr(mbrs[i]);
204 }
205 return 0;
206 }
207
208 fprintf(backup, "%d ", mbr->array[0].addrlo);
209 for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++)
210 {
211 fprintf(backup, "'%s %d %d' ", mbr->array[part_cnt].name,
212 mbr->array[part_cnt].lenlo, mbr->array[part_cnt].user_type);
213 }
214 fprintf(backup, "\n");
215 fclose(backup);
216
217 mbr->PartCount = nparts + partoffset;
218 if (partoffset)
219 start = mbr->array[0].addrlo + mbr->array[0].lenlo;
220 for(i = 0; i < nparts; i++) {
221 strcpy((char *)mbr->array[i+partoffset].name, names[i]);
222 strcpy((char *)mbr->array[i+partoffset].classname, "DISK");
223 memset((void *) mbr->array[i+partoffset].res, 0, sizeof(mbr->array[i+partoffset].res));
224 mbr->array[i+partoffset].user_type = user_types[i];
225 mbr->array[i+partoffset].ro = 0;
226 mbr->array[i+partoffset].addrhi = 0;
227 mbr->array[i+partoffset].lenhi = 0;
228 mbr->array[i+partoffset].addrlo = start;
229 mbr->array[i+partoffset].lenlo = lens[i];
230 start += lens[i];
231 }
232
233 printf("\nready to write new partition tables:\n");
234 printmbr(mbr);
235 for (i = 0; i < MBR_COPY_NUM; i++) {
236 if (mbrs[i])
237 _free_mbr(mbrs[i]);
238 }
239 printf("\nwrite new partition tables? (Y/N)\n");
240 read(0, &yn, 1);
241 if (yn != 'Y' && yn != 'y') {
242 printf("aborting\n");
243 return 0;
244 }
245
246 for (i = 0; i < MBR_COPY_NUM; i++) {
247 mbr->index = i;
248 // calculate new checksum
249 *(__u32 *)mbr = calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4);
250 lseek(fd,MBR_START_ADDRESS + MBR_SIZE*i,SEEK_SET);
251 write(fd,mbr,MBR_SIZE);
252 }
253
254 #ifdef __linux__
255 if (ioctl(fd, BLKRRPART, NULL))
256 perror("Failed rereading partition table");
257 #endif
258
259 return 1;
260 }
261
nand_part(int argc,char ** argv,const char * cmd,int fd,int force)262 int nand_part (int argc, char **argv, const char *cmd, int fd, int force)
263 {
264 int partoffset = 0;
265 int i;
266 char names[MAX_PART_COUNT][MAX_NAME];
267 __u32 lens[MAX_PART_COUNT];
268 unsigned int user_types[MAX_PART_COUNT];
269 __u32 start;
270
271
272 // parse name/len arguments
273 memset((void *) user_types, 0, sizeof(user_types));
274 if (argc > 0) {
275 if (sscanf(argv[0], "%u", &start) != 1) {
276 partoffset++;
277 if (force) {
278 printf("if using -f, must set info for first partition\n");
279 usage(cmd);
280 close(fd);
281 return -3;
282 }
283 }
284 else {
285 argc--;
286 argv++;
287 }
288
289 if (start < MBR_SIZE * MBR_COPY_NUM / 512) {
290 printf("Partition 1 starting offset must be at least %d\n", MBR_SIZE * MBR_COPY_NUM / 512);
291 close(fd);
292 return -3;
293 }
294
295 for (i = 0; i < argc; i++) {
296 if (sscanf(argv[i], "%s %d %d", names[i], &lens[i], &user_types[i]) < 2) {
297 printf("bad 'name len' argument\n");
298 usage(cmd);
299 close(fd);
300 return -3;
301 }
302 }
303 }
304
305 checkmbrs(fd);
306
307 if (argc > MAX_PART_COUNT - partoffset) {
308 printf("too many partitions specified (MAX 14)\n");
309 usage(cmd);
310 close(fd);
311 return -2;
312 }
313
314
315 if (argc > 0) {
316 if (writembrs(fd, names, start, lens, user_types, argc, partoffset, force)) {
317 printf("\nverifying new partition tables:\n");
318 checkmbrs(fd);
319 #ifdef __linux__
320 printf("rereading partition table... returned %d\n", ioctl(fd, BLKRRPART, 0));
321 #endif
322 }
323 }
324 close(fd);
325
326 return 0;
327 }
328