mbr: move mbr related codes / add mbr default command
[kernel/u-boot.git] / drivers / misc / mbr.c
1 /*
2  * Copyright (C) 2010 Samsung Electrnoics
3  * Kyungmin Park <kyungmin.park@samsung.com>
4  */
5
6 #include <common.h>
7 #include <mbr.h>
8 #include <mmc.h>
9
10 #define SIGNATURE       ((unsigned short) 0xAA55)
11
12 unsigned int mbr_offset[16];
13 unsigned int mbr_parts = 0;
14
15 static int logical = 4;
16 static int extended_lba;
17
18 static inline void set_chs_value(struct mbr_partition *part, int part_num)
19 {
20         /* FIXME */
21         if (part_num == 0) {
22                 part->f_chs[0] = 0x01;
23                 part->f_chs[1] = 0x01;
24                 part->f_chs[2] = 0x00;
25         } else {
26                 part->f_chs[0] = 0x03;
27                 part->f_chs[1] = 0xd0;
28                 part->f_chs[2] = 0xff;
29         }
30         part->l_chs[0] = 0x03;
31         part->l_chs[1] = 0xd0;
32         part->l_chs[2] = 0xff;
33 }
34
35 void set_mbr_table(unsigned int start_addr, int parts,
36                 unsigned int *blocks, unsigned int *part_offset)
37 {
38         struct mmc *mmc = find_mmc_device(0);
39         struct mbr mbr_table;
40         unsigned int offset = start_addr;
41         unsigned int max = 0;
42         unsigned int size = 0;
43         int i, j;
44
45         mmc_init(mmc);
46         max = mmc->capacity / mmc->read_bl_len;
47
48         memset(&mbr_table, 0, sizeof(struct mbr));
49
50         mbr_table.signature = SIGNATURE;
51
52         if (blocks[parts - 1] == 0) {
53                 size = start_addr;
54                 for (i = 0; i < parts; i++)
55                         size += blocks[i];
56                 blocks[parts - 1] = max - size;
57         }
58
59         /* Primary */
60         for (i = 0; i < 3; i++) {
61                 mbr_table.parts[i].partition_type = 0x83;       /* Linux */
62                 mbr_table.parts[i].lba = offset;
63                 mbr_table.parts[i].nsectors = blocks[i];
64                 part_offset[i] = offset;
65                 offset += blocks[i];
66
67                 set_chs_value(&mbr_table.parts[i], i);
68         }
69
70         if (parts < 4) {
71                 mmc->block_dev.block_write(0, 0, 1, &mbr_table);
72                 return;
73         }
74
75         /* Extended */
76         mbr_table.parts[i].partition_type = 0x05;       /* Extended */
77         mbr_table.parts[i].lba = offset;
78         mbr_table.parts[i].nsectors = max - offset;
79         set_chs_value(&mbr_table.parts[i], i);
80
81         mmc->block_dev.block_write(0, 0, 1, &mbr_table);
82
83         for (; i < parts; i++) {
84                 struct mbr ebr_table;
85                 memset(&ebr_table, 0, sizeof(struct mbr));
86
87                 ebr_table.signature = SIGNATURE;
88
89                 for (j = 0; j < 2; j++) {
90                         if (j == 0) {
91                                 blocks[parts - 1] -= 0x10;
92                                 ebr_table.parts[j].partition_type = 0x83;
93                                 ebr_table.parts[j].lba = 0x10;
94                                 ebr_table.parts[j].nsectors = blocks[i];
95                                 set_chs_value(&ebr_table.parts[j], i);
96                         } else {
97                                 if (parts != i + 1) {
98                                         ebr_table.parts[j].partition_type = 0x05;
99                                         ebr_table.parts[j].lba = 0x10 + blocks[i];
100                                         ebr_table.parts[j].nsectors = blocks[i + 1];
101                                         set_chs_value(&ebr_table.parts[j], i);
102                                 }
103                         }
104                 }
105
106                 mmc->block_dev.block_write(0, offset, 1, &ebr_table);
107
108                 offset += ebr_table.parts[0].lba;
109                 part_offset[i] = offset;
110                 offset += ebr_table.parts[0].nsectors;
111         }
112 }
113
114 static int get_ebr_table(struct mmc *mmc, struct mbr_partition *mp,
115                 int ebr_next, unsigned int *part_offset, int parts)
116 {
117         struct mbr *ebr;
118         struct mbr_partition *p;
119         char buf[512];
120         int ret, i;
121         int lba = 0;
122
123         if (ebr_next)
124                 lba = extended_lba;
125
126         lba += mp->lba;
127         ret = mmc->block_dev.block_read(0, lba, 1, buf);
128         if (ret != 1) {
129                 printf("%s[%d] mmc_read_blocks %d\n", __func__, __LINE__, ret);
130                 return 0;
131         }
132         ebr = (struct mbr *) buf;
133
134         if (ebr->signature != SIGNATURE) {
135                 printf("Signature error 0x%x\n", ebr->signature);
136                 return 0;
137         }
138
139         for (i = 0; i < 2; i++) {
140                 p = (struct mbr_partition *) &ebr->parts[i];
141
142                 if (i == 0) {
143                         logical++;
144                         lba += p->lba;
145                         if (p->partition_type == 0x83) {
146                                 part_offset[parts] = lba;
147                                 parts++;
148                         }
149                 }
150         }
151
152         if (p->lba && p->partition_type == 0x5)
153                 parts = get_ebr_table(mmc, p, 1, part_offset, parts);
154
155         return parts;
156 }
157
158 int get_mbr_table(unsigned int *part_offset)
159 {
160         struct mmc *mmc = find_mmc_device(0);
161         struct mbr_partition *mp;
162         struct mbr *mbr;
163         char buf[512];
164         int ret, i;
165         int parts = 0;
166
167         mmc_init(mmc);
168
169         ret = mmc->block_dev.block_read(0, 0, 1, buf);
170         if (ret != 1) {
171                 printf("%s[%d] mmc_read_blocks %d\n", __func__, __LINE__, ret);
172                 return 0;
173         }
174
175         mbr = (struct mbr *) buf;
176
177         if (mbr->signature != SIGNATURE)
178                 printf("Signature error 0x%x\n", mbr->signature);
179
180         logical = 4;
181
182         for (i = 0; i < 4; i++) {
183                 mp = (struct mbr_partition *) &mbr->parts[i];
184
185                 if (!mp->partition_type)
186                         continue;
187
188                 if (mp->partition_type == 0x83) {
189                         part_offset[parts] = mp->lba;
190                         parts++;
191                 }
192
193                 if (mp->lba && mp->partition_type == 0x5) {
194                         extended_lba = mp->lba;
195                         parts = get_ebr_table(mmc, mp, 0, part_offset, parts);
196                 }
197         }
198
199         return parts;
200 }
201
202 static inline int get_cylinder(char chs1, char chs2, int *sector)
203 {
204         *sector = chs1 & 0x3f;
205
206         return ((chs1 & 0xc0) << 2) | chs2;
207 }
208
209 static void ebr_show(struct mmc *mmc, struct mbr_partition *mp, int ebr_next)
210 {
211         struct mbr *ebr;
212         struct mbr_partition *p;
213         char buf[512];
214         int ret, i, sector, cylinder;
215         int lba = 0;
216
217         if (ebr_next)
218                 lba = extended_lba;
219
220         lba += mp->lba;
221         printf(">>> Read sector from 0x%08x (LBA: 0x%08x + 0x%x)\n",
222                 lba, mp->lba, (lba == mp->lba) ? 0 : lba - mp->lba);
223
224         ret = mmc->block_dev.block_read(0, lba, 1, buf);
225         if (ret != 1) {
226                 printf("%s[%d] mmc_read_blocks %d\n", __func__, __LINE__, ret);
227                 return;
228         }
229         ebr = (struct mbr *) buf;
230
231         if (ebr->signature != SIGNATURE) {
232                 printf("Signature error 0x%x\n", ebr->signature);
233                 return;
234         }
235
236         for (i = 0; i < 2; i++) {
237                 p = (struct mbr_partition *) &ebr->parts[i];
238
239                 if (i == 0) {
240                         logical++;
241                         lba += p->lba;
242                         printf("Extended Part %d\n", logical);
243                 } else
244                         printf("Extended Part next\n");
245
246                 printf("status   0x%02x\n", p->status);
247                 printf("head     0x%02x,", p->f_chs[0]);
248                 cylinder = get_cylinder(p->f_chs[1], p->f_chs[2], &sector);
249                 printf("\tsector   0x%02x,", sector);
250                 printf("\tcylinder 0x%04x\n", cylinder);
251                 printf("type     0x%02x\n", p->partition_type);
252                 printf("head     0x%02x,", p->l_chs[0]);
253                 cylinder = get_cylinder(p->l_chs[1], p->l_chs[2], &sector);
254                 printf("\tsector   0x%02x,", sector);
255                 printf("\tcylinder 0x%04x\n", cylinder);
256                 printf("lba      0x%08x (%d), ", p->lba, p->lba);
257                 printf("nsectors 0x%08x (%d)\n", p->nsectors, p->nsectors);
258         }
259
260         if (p->lba && p->partition_type == 0x5)
261                 ebr_show(mmc, p, 1);
262 }
263
264 static void mbr_show(void)
265 {
266         struct mmc *mmc = find_mmc_device(0);
267         struct mbr_partition *mp;
268         struct mbr *mbr;
269         char buf[512];
270         int ret, i;
271         int cylinder;
272
273         mmc_init(mmc);
274
275         ret = mmc->block_dev.block_read(0, 0, 1, buf);
276         if (ret != 1) {
277                 printf("%s[%d] mmc_read_blocks %d\n", __func__, __LINE__, ret);
278                 return;
279         }
280
281         mbr = (struct mbr *) buf;
282
283         if (mbr->signature != SIGNATURE)
284                 printf("Signature error 0x%x\n", mbr->signature);
285
286         logical = 4;
287         printf("MBR partition info\n");
288         for (i = 0; i < 4; i++) {
289                 mp = (struct mbr_partition *) &mbr->parts[i];
290
291                 if (!mp->partition_type)
292                         continue;
293
294                 printf("Part %d\n", i + 1);
295                 printf("status   0x%02x\n", mp->status);
296                 printf("head     0x%02x,", mp->f_chs[0]);
297                 printf("\tsector   0x%02x,", mp->f_chs[1] & 0x3f);
298                 cylinder = (mp->f_chs[1] & 0xc0) << 2;
299                 cylinder |= mp->f_chs[2];
300                 printf("\tcylinder 0x%04x\n", cylinder);
301                 printf("type     0x%02x\n", mp->partition_type);
302                 printf("head     0x%02x,", mp->l_chs[0]);
303                 printf("\tsector   0x%02x,", mp->l_chs[1] & 0x3f);
304                 cylinder = (mp->l_chs[1] & 0xc0) << 2;
305                 cylinder |= mp->l_chs[2];
306                 printf("\tcylinder 0x%04x\n", cylinder);
307                 printf("lba      0x%08x (%d), ", mp->lba, mp->lba);
308                 printf("nsectors 0x%08x (%d)\n", mp->nsectors, mp->nsectors);
309
310                 if (mp->lba && mp->partition_type == 0x5) {
311                         extended_lba = mp->lba;
312                         ebr_show(mmc, mp, 0);
313                 }
314         }
315 }
316
317 static unsigned long memsize_parse (const char *const ptr, const char **retptr)
318 {
319         unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
320
321         switch (**retptr) {
322                 case 'G':
323                 case 'g':
324                         ret <<= 10;
325                 case 'M':
326                 case 'm':
327                         ret <<= 10;
328                 case 'K':
329                 case 'k':
330                         ret <<= 10;
331                         (*retptr)++;
332                 default:
333                         break;
334         }
335
336         return ret;
337 }
338
339 void set_mbr_info(char *ramaddr, unsigned int len)
340 {
341         char mbr_str[256];
342         char save[16][16];
343         char *p;
344         char *tok;
345         unsigned int size[16];
346         int i = 0;
347
348         strncpy(mbr_str, ramaddr, len);
349         p = mbr_str;
350
351         for (i = 0; ; i++, p = NULL) {
352                 tok = strtok(p, ",");
353                 if (tok == NULL)
354                         break;
355                 strcpy(save[i], tok);
356                 printf("part%d: %s\n", i, save[i]);
357         }
358
359         mbr_parts = i;
360         printf("find %d partitions\n", mbr_parts);
361
362         for (i = 0; i < mbr_parts; i++) {
363                 p = save[i];
364                 size[i] = memsize_parse(p, (const char **)&p) / 512;
365         }
366
367         puts("save the MBR Table...\n");
368         set_mbr_table(0x800, mbr_parts, size, mbr_offset);
369 }
370
371 static void mbr_default(void)
372 {
373         char *mbrparts;
374
375         puts("using default MBR\n");
376
377         mbrparts = getenv("mbrparts");
378         set_mbr_info(mbrparts, strlen(mbrparts));
379 }
380
381 static int do_mbr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
382 {
383         switch (argc) {
384         case 2:
385                 if (strncmp(argv[1], "show", 2) == 0)
386                         mbr_show();
387                 else if (strncmp(argv[1], "default", 3) == 0)
388                         mbr_default();
389                 break;
390         default:
391                 cmd_usage(cmdtp);
392                 return 1;
393         }
394
395         return 0;
396 }
397
398 U_BOOT_CMD(
399         mbr,    CONFIG_SYS_MAXARGS,     1, do_mbr,
400         "Master Boot Record",
401         "show - show MBR\n"
402         "mbr default - reset MBR partition to defaults\n"
403 );