source: mainline/uspace/lib/label/src/mbr.c@ b7a4d06

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b7a4d06 was b7a4d06, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Most of extended (but not logical) partition support.

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup liblabel
30 * @{
31 */
32/**
33 * @file Master Boot Record label
34 */
35
36#include <block.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <mem.h>
40#include <stdlib.h>
41
42#include "std/mbr.h"
43#include "mbr.h"
44
45static int mbr_open(service_id_t, label_t **);
46static int mbr_create(service_id_t, label_t **);
47static void mbr_close(label_t *);
48static int mbr_destroy(label_t *);
49static int mbr_get_info(label_t *, label_info_t *);
50static label_part_t *mbr_part_first(label_t *);
51static label_part_t *mbr_part_next(label_part_t *);
52static void mbr_part_get_info(label_part_t *, label_part_info_t *);
53static int mbr_part_create(label_t *, label_part_spec_t *, label_part_t **);
54static int mbr_part_destroy(label_part_t *);
55
56static void mbr_unused_pte(mbr_pte_t *);
57static int mbr_part_to_pte(label_part_t *, mbr_pte_t *);
58static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
59static int mbr_pte_update(label_t *, mbr_pte_t *, int);
60
61label_ops_t mbr_label_ops = {
62 .open = mbr_open,
63 .create = mbr_create,
64 .close = mbr_close,
65 .destroy = mbr_destroy,
66 .get_info = mbr_get_info,
67 .part_first = mbr_part_first,
68 .part_next = mbr_part_next,
69 .part_get_info = mbr_part_get_info,
70 .part_create = mbr_part_create,
71 .part_destroy = mbr_part_destroy
72};
73
74static int mbr_open(service_id_t sid, label_t **rlabel)
75{
76 label_t *label = NULL;
77 mbr_br_block_t *mbr = NULL;
78 mbr_pte_t *eptr;
79 uint16_t sgn;
80 size_t bsize;
81 aoff64_t nblocks;
82 uint32_t entry;
83 int rc;
84
85 rc = block_get_bsize(sid, &bsize);
86 if (rc != EOK) {
87 rc = EIO;
88 goto error;
89 }
90
91 rc = block_get_nblocks(sid, &nblocks);
92 if (rc != EOK) {
93 rc = EIO;
94 goto error;
95 }
96
97 if (bsize < 512 || (bsize % 512) != 0) {
98 rc = EINVAL;
99 goto error;
100 }
101
102 if (nblocks < mbr_ablock0) {
103 rc = EINVAL;
104 goto error;
105 }
106
107 mbr = calloc(1, bsize);
108 if (mbr == NULL) {
109 rc = ENOMEM;
110 goto error;
111 }
112
113 rc = block_read_direct(sid, mbr_ba, 1, mbr);
114 if (rc != EOK) {
115 rc = EIO;
116 goto error;
117 }
118
119 label = calloc(1, sizeof(label_t));
120 if (label == NULL)
121 return ENOMEM;
122
123 list_initialize(&label->parts);
124 list_initialize(&label->pri_parts);
125 list_initialize(&label->log_parts);
126
127 /* Verify boot record signature */
128 sgn = uint16_t_le2host(mbr->signature);
129 if (sgn != mbr_br_signature) {
130 rc = EIO;
131 goto error;
132 }
133
134 label->ext_part_idx = -1;
135 for (entry = 0; entry < mbr_nprimary; entry++) {
136 eptr = &mbr->pte[entry];
137 rc = mbr_pte_to_part(label, eptr, entry + 1);
138 if (rc != EOK)
139 goto error;
140 }
141
142 free(mbr);
143 mbr = NULL;
144
145 label->ops = &mbr_label_ops;
146 label->ltype = lt_mbr;
147 label->svc_id = sid;
148 label->block_size = bsize;
149 label->ablock0 = mbr_ablock0;
150 label->anblocks = nblocks - mbr_ablock0;
151 label->pri_entries = mbr_nprimary;
152 *rlabel = label;
153 return EOK;
154error:
155 free(mbr);
156 free(label);
157 return rc;
158}
159
160static int mbr_create(service_id_t sid, label_t **rlabel)
161{
162 label_t *label = NULL;
163 mbr_br_block_t *mbr = NULL;
164 aoff64_t nblocks;
165 size_t bsize;
166 int i;
167 int rc;
168
169 rc = block_get_bsize(sid, &bsize);
170 if (rc != EOK) {
171 rc = EIO;
172 goto error;
173 }
174
175 rc = block_get_nblocks(sid, &nblocks);
176 if (rc != EOK) {
177 rc = EIO;
178 goto error;
179 }
180
181 mbr = calloc(1, bsize);
182 if (mbr == NULL) {
183 rc = ENOMEM;
184 goto error;
185 }
186
187 label = calloc(1, sizeof(label_t));
188 if (label == NULL)
189 return ENOMEM;
190
191 list_initialize(&label->parts);
192 list_initialize(&label->pri_parts);
193 list_initialize(&label->log_parts);
194
195 mbr->media_id = 0;
196 mbr->pad0 = 0;
197 for (i = 0; i < mbr_nprimary; i++)
198 mbr_unused_pte(&mbr->pte[i]);
199 mbr->signature = host2uint16_t_le(mbr_br_signature);
200
201 rc = block_write_direct(sid, mbr_ba, 1, mbr);
202 if (rc != EOK) {
203 rc = EIO;
204 goto error;
205 }
206
207 free(mbr);
208 mbr = NULL;
209
210 label->ops = &mbr_label_ops;
211 label->ltype = lt_mbr;
212 label->block_size = bsize;
213 label->svc_id = sid;
214 label->ablock0 = mbr_ablock0;
215 label->anblocks = nblocks - mbr_ablock0;
216 label->pri_entries = mbr_nprimary;
217 label->ext_part_idx = -1;
218
219 *rlabel = label;
220 return EOK;
221error:
222 free(mbr);
223 free(label);
224 return rc;
225}
226
227static void mbr_close(label_t *label)
228{
229 label_part_t *part;
230
231 part = mbr_part_first(label);
232 while (part != NULL) {
233 list_remove(&part->lparts);
234 if (link_used(&part->lpri))
235 list_remove(&part->lpri);
236 if (link_used(&part->llog))
237 list_remove(&part->llog);
238 free(part);
239
240 part = mbr_part_first(label);
241 }
242
243 free(label);
244}
245
246static int mbr_destroy(label_t *label)
247{
248 mbr_br_block_t *mbr = NULL;
249 label_part_t *part;
250 int rc;
251
252 part = mbr_part_first(label);
253 if (part != NULL) {
254 rc = ENOTEMPTY;
255 goto error;
256 }
257
258 mbr = calloc(1, label->block_size);
259 if (mbr == NULL) {
260 rc = ENOMEM;
261 goto error;
262 }
263
264 rc = block_write_direct(label->svc_id, mbr_ba, 1, mbr);
265 if (rc != EOK) {
266 rc = EIO;
267 goto error;
268 }
269
270 free(mbr);
271 mbr = NULL;
272
273 free(label);
274 return EOK;
275error:
276 free(mbr);
277 return rc;
278}
279
280static int mbr_get_info(label_t *label, label_info_t *linfo)
281{
282 memset(linfo, 0, sizeof(label_info_t));
283 linfo->dcnt = dc_label;
284 linfo->ltype = lt_mbr;
285
286 /* We support extended partitions */
287 linfo->flags = lf_ext_supp;
288
289 /** Can create primary if there is a free slot */
290 if (list_count(&label->pri_parts) < mbr_nprimary)
291 linfo->flags |= lf_can_create_pri;
292 /* Can create extended if there is a free slot and no extended */
293 if ((linfo->flags & lf_can_create_pri) != 0 && label->ext_part_idx < 0)
294 linfo->flags |= lf_can_create_ext;
295 /* Can create logical if there is an extended partition */
296 if (label->ext_part_idx >= 0)
297 linfo->flags |= lf_can_create_log;
298
299 linfo->ablock0 = label->ablock0;
300 linfo->anblocks = label->anblocks;
301
302 return EOK;
303}
304
305static label_part_t *mbr_part_first(label_t *label)
306{
307 link_t *link;
308
309 link = list_first(&label->parts);
310 if (link == NULL)
311 return NULL;
312
313 return list_get_instance(link, label_part_t, lparts);
314}
315
316static label_part_t *mbr_part_next(label_part_t *part)
317{
318 link_t *link;
319
320 link = list_next(&part->lparts, &part->label->parts);
321 if (link == NULL)
322 return NULL;
323
324 return list_get_instance(link, label_part_t, lparts);
325}
326
327#include <io/log.h>
328static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
329{
330 pinfo->index = part->index;
331 pinfo->block0 = part->block0;
332 pinfo->nblocks = part->nblocks;
333
334 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_get_info: index=%d ptype=%d",
335 (int)part->index, (int)part->ptype);
336 if (link_used(&part->llog))
337 pinfo->pkind = lpk_logical;
338 else if (part->ptype == mbr_pt_extended)
339 pinfo->pkind = lpk_extended;
340 else
341 pinfo->pkind = lpk_primary;
342}
343
344static int mbr_part_create(label_t *label, label_part_spec_t *pspec,
345 label_part_t **rpart)
346{
347 label_part_t *part;
348 mbr_pte_t pte;
349 int rc;
350
351 part = calloc(1, sizeof(label_part_t));
352 if (part == NULL)
353 return ENOMEM;
354
355
356 /* XXX Check if index is used */
357
358 part->label = label;
359 part->index = pspec->index;
360 part->block0 = pspec->block0;
361 part->nblocks = pspec->nblocks;
362
363 switch (pspec->pkind) {
364 case lpk_primary:
365 part->ptype = pspec->ptype;
366 break;
367 case lpk_extended:
368 part->ptype = mbr_pt_extended;
369 if (pspec->ptype != 0) {
370 rc = EINVAL;
371 goto error;
372 }
373 if (label->ext_part_idx >= 0) {
374 rc = EEXISTS;
375 goto error;
376 }
377 break;
378 case lpk_logical:
379 part->ptype = pspec->ptype;
380 if (pspec->index != 0) {
381 rc = EINVAL;
382 goto error;
383 }
384 break;
385 }
386
387 if (pspec->pkind != lpk_logical) {
388 /* Primary or extended partition */
389 /* XXX Verify index, block0, nblocks */
390
391 if (pspec->index < 1 || pspec->index > label->pri_entries) {
392 rc = EINVAL;
393 goto error;
394 }
395
396 rc = mbr_part_to_pte(part, &pte);
397 if (rc != EOK) {
398 rc = EINVAL;
399 goto error;
400 }
401
402 rc = mbr_pte_update(label, &pte, pspec->index - 1);
403 if (rc != EOK) {
404 rc = EIO;
405 goto error;
406 }
407
408 list_append(&part->lparts, &label->parts);
409 list_append(&part->lpri, &label->pri_parts);
410
411 if (pspec->pkind == lpk_extended)
412 label->ext_part_idx = pspec->index - 1;
413 } else {
414 /* Logical partition */
415 rc = ENOTSUP;
416 goto error;
417 }
418
419 *rpart = part;
420 return EOK;
421error:
422 free(part);
423 return rc;
424}
425
426static int mbr_part_destroy(label_part_t *part)
427{
428 mbr_pte_t pte;
429 int rc;
430
431 /* Prepare unused partition table entry */
432 mbr_unused_pte(&pte);
433
434 /* Modify partition table */
435 rc = mbr_pte_update(part->label, &pte, part->index - 1);
436 if (rc != EOK)
437 return EIO;
438
439 /* If it was the extended partition, clear ext. part. index */
440 if (part->index - 1 == part->label->ext_part_idx)
441 part->label->ext_part_idx = -1;
442
443 list_remove(&part->lparts);
444 if (link_used(&part->lpri))
445 list_remove(&part->lpri);
446 if (link_used(&part->llog))
447 list_remove(&part->llog);
448 free(part);
449 return EOK;
450}
451
452static void mbr_unused_pte(mbr_pte_t *pte)
453{
454 memset(pte, 0, sizeof(mbr_pte_t));
455}
456
457static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
458{
459 if ((part->block0 >> 32) != 0)
460 return EINVAL;
461 if ((part->nblocks >> 32) != 0)
462 return EINVAL;
463 if ((part->ptype >> 8) != 0)
464 return EINVAL;
465
466 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_to_pte: a0=%" PRIu64
467 " len=%" PRIu64 " ptype=%d", part->block0, part->nblocks,
468 (int)part->ptype);
469 memset(pte, 0, sizeof(mbr_pte_t));
470 pte->ptype = part->ptype;
471 pte->first_lba = host2uint32_t_le(part->block0);
472 pte->length = host2uint32_t_le(part->nblocks);
473 return EOK;
474}
475
476static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
477{
478 label_part_t *part;
479 uint32_t block0;
480 uint32_t nblocks;
481
482 block0 = uint32_t_le2host(pte->first_lba);
483 nblocks = uint32_t_le2host(pte->length);
484
485 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
486 if (pte->ptype == mbr_pt_unused || nblocks == 0)
487 return EOK;
488
489 part = calloc(1, sizeof(label_part_t));
490 if (part == NULL)
491 return ENOMEM;
492
493 part->ptype = pte->ptype;
494 part->index = index;
495 part->block0 = block0;
496 part->nblocks = nblocks;
497
498 /*
499 * TODO: Verify
500 * - partition must reside on disk
501 * - partition must not overlap any other partition
502 */
503
504 part->label = label;
505 list_append(&part->lparts, &label->parts);
506 list_append(&part->lpri, &label->pri_parts);
507
508 if (pte->ptype == mbr_pt_extended)
509 label->ext_part_idx = index - 1;
510 return EOK;
511}
512
513/** Update partition table entry at specified index.
514 *
515 * Replace partition entry at index @a index with the contents of
516 * @a pte.
517 */
518static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
519{
520 mbr_br_block_t *br;
521 int rc;
522
523 br = calloc(1, label->block_size);
524 if (br == NULL)
525 return ENOMEM;
526
527 rc = block_read_direct(label->svc_id, mbr_ba, 1, br);
528 if (rc != EOK) {
529 rc = EIO;
530 goto error;
531 }
532
533 br->pte[index] = *pte;
534
535 rc = block_write_direct(label->svc_id, mbr_ba, 1, br);
536 if (rc != EOK) {
537 rc = EIO;
538 goto error;
539 }
540
541 free(br);
542 return EOK;
543error:
544 free(br);
545 return rc;
546}
547
548/** @}
549 */
Note: See TracBrowser for help on using the repository browser.