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