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