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

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

Information structures need updating to new model.

  • Property mode set to 100644
File size: 23.1 KB
RevLine 
[3faa03d]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>
[1626cd4]39#include <mem.h>
[3faa03d]40#include <stdlib.h>
41
42#include "std/mbr.h"
43#include "mbr.h"
44
45static int mbr_open(service_id_t, label_t **);
[c02d098]46static int mbr_open_ext(label_t *);
[3faa03d]47static int mbr_create(service_id_t, label_t **);
48static void mbr_close(label_t *);
49static int mbr_destroy(label_t *);
[1626cd4]50static int mbr_get_info(label_t *, label_info_t *);
[3faa03d]51static label_part_t *mbr_part_first(label_t *);
52static label_part_t *mbr_part_next(label_part_t *);
53static void mbr_part_get_info(label_part_t *, label_part_info_t *);
54static int mbr_part_create(label_t *, label_part_spec_t *, label_part_t **);
55static int mbr_part_destroy(label_part_t *);
[f57ccb5]56static int mbr_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
[3faa03d]57
[99c23405]58static void mbr_unused_pte(mbr_pte_t *);
59static int mbr_part_to_pte(label_part_t *, mbr_pte_t *);
[1626cd4]60static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
[c02d098]61static int mbr_pte_to_log_part(label_t *, uint64_t, mbr_pte_t *);
62static void mbr_log_part_to_ptes(label_part_t *, mbr_pte_t *, mbr_pte_t *);
[99c23405]63static int mbr_pte_update(label_t *, mbr_pte_t *, int);
[c02d098]64static int mbr_log_part_insert(label_t *, label_part_t *);
65static int mbr_ebr_create(label_t *, label_part_t *);
66static int mbr_ebr_delete(label_t *, label_part_t *);
67static int mbr_ebr_update_next(label_t *, label_part_t *);
68static void mbr_update_log_indices(label_t *);
[3faa03d]69
70label_ops_t mbr_label_ops = {
71 .open = mbr_open,
72 .create = mbr_create,
73 .close = mbr_close,
74 .destroy = mbr_destroy,
[1626cd4]75 .get_info = mbr_get_info,
[3faa03d]76 .part_first = mbr_part_first,
77 .part_next = mbr_part_next,
78 .part_get_info = mbr_part_get_info,
79 .part_create = mbr_part_create,
[f57ccb5]80 .part_destroy = mbr_part_destroy,
81 .suggest_ptype = mbr_suggest_ptype
[3faa03d]82};
83
84static int mbr_open(service_id_t sid, label_t **rlabel)
85{
86 label_t *label = NULL;
87 mbr_br_block_t *mbr = NULL;
88 mbr_pte_t *eptr;
89 uint16_t sgn;
90 size_t bsize;
[1626cd4]91 aoff64_t nblocks;
[3faa03d]92 uint32_t entry;
93 int rc;
94
95 rc = block_get_bsize(sid, &bsize);
96 if (rc != EOK) {
97 rc = EIO;
98 goto error;
99 }
100
[1626cd4]101 rc = block_get_nblocks(sid, &nblocks);
102 if (rc != EOK) {
103 rc = EIO;
104 goto error;
105 }
106
[3faa03d]107 if (bsize < 512 || (bsize % 512) != 0) {
108 rc = EINVAL;
109 goto error;
110 }
111
[1626cd4]112 if (nblocks < mbr_ablock0) {
113 rc = EINVAL;
114 goto error;
115 }
116
[3faa03d]117 mbr = calloc(1, bsize);
118 if (mbr == NULL) {
119 rc = ENOMEM;
120 goto error;
121 }
122
[1626cd4]123 rc = block_read_direct(sid, mbr_ba, 1, mbr);
[3faa03d]124 if (rc != EOK) {
125 rc = EIO;
126 goto error;
127 }
128
129 label = calloc(1, sizeof(label_t));
130 if (label == NULL)
131 return ENOMEM;
132
133 list_initialize(&label->parts);
[b7a4d06]134 list_initialize(&label->pri_parts);
135 list_initialize(&label->log_parts);
[3faa03d]136
137 /* Verify boot record signature */
138 sgn = uint16_t_le2host(mbr->signature);
139 if (sgn != mbr_br_signature) {
140 rc = EIO;
141 goto error;
142 }
143
[c02d098]144
145 label->ext_part = NULL;
[3faa03d]146 for (entry = 0; entry < mbr_nprimary; entry++) {
147 eptr = &mbr->pte[entry];
[1626cd4]148 rc = mbr_pte_to_part(label, eptr, entry + 1);
[3faa03d]149 if (rc != EOK)
150 goto error;
151 }
152
153 free(mbr);
154 mbr = NULL;
155
156 label->ops = &mbr_label_ops;
157 label->ltype = lt_mbr;
[603c1d1f]158 label->svc_id = sid;
159 label->block_size = bsize;
[1626cd4]160 label->ablock0 = mbr_ablock0;
161 label->anblocks = nblocks - mbr_ablock0;
[99c23405]162 label->pri_entries = mbr_nprimary;
[c02d098]163
164 if (label->ext_part != NULL) {
165 /* Open extended partition */
166 rc = mbr_open_ext(label);
167 if (rc != EOK)
168 goto error;
169 }
170
[3faa03d]171 *rlabel = label;
172 return EOK;
173error:
174 free(mbr);
[c02d098]175 mbr_close(label);
176 return rc;
177}
178
179/** Open extended partition */
180static int mbr_open_ext(label_t *label)
181{
182 mbr_br_block_t *ebr = NULL;
183 mbr_pte_t *ethis;
184 mbr_pte_t *enext;
185 uint64_t ebr_b0;
186 uint64_t ebr_nblocks_min;
187 uint64_t ebr_nblocks_max;
188 uint64_t pebr_b0;
189 uint64_t pebr_nblocks;
190 uint64_t pb0;
191 uint64_t pnblocks;
192 uint64_t ep_b0;
193 int rc;
194
195 ebr = calloc(1, label->block_size);
196 if (ebr == NULL) {
197 rc = ENOMEM;
198 goto error;
199 }
200
201 /* First block of extended partition */
202 ep_b0 = label->ext_part->block0;
203
204 /* First block of current EBR */
205 ebr_b0 = label->ext_part->block0;
206
207 /*
208 * We don't have bounds for the first EBR, so for purpose of
209 * verification let's say it contains at least one block and
210 * at most all blocks from the extended partition.
211 */
212 ebr_nblocks_min = 1;
213 ebr_nblocks_max = label->ext_part->nblocks;
214
215 while (true) {
216 /* Read EBR */
217 rc = block_read_direct(label->svc_id, ebr_b0, 1, ebr);
218 if (rc != EOK) {
219 rc = EIO;
220 goto error;
221 }
222
223 ethis = &ebr->pte[mbr_ebr_pte_this];
224 enext = &ebr->pte[mbr_ebr_pte_next];
225
226 pb0 = ebr_b0 + uint32_t_le2host(ethis->first_lba);
227 pnblocks = uint32_t_le2host(ethis->length);
228
229 if (ethis->ptype == mbr_pt_unused || pnblocks == 0)
230 break;
231
232 /* Verify partition lies within the range of EBR */
233 if (pb0 + pnblocks > ebr_b0 + ebr_nblocks_max) {
234 rc = EIO;
235 goto error;
236 }
237
238 /* Create partition structure */
239 rc = mbr_pte_to_log_part(label, ebr_b0, ethis);
240 if (rc != EOK) {
[22747e8]241 rc = EIO;
[c02d098]242 goto error;
243 }
244
245 /* Save previous EBR range */
246 pebr_b0 = ebr_b0;
247 pebr_nblocks = ebr_nblocks_min;
248
249 /* Proceed to next EBR */
250 ebr_b0 = ep_b0 + uint32_t_le2host(enext->first_lba);
251 ebr_nblocks_min = uint32_t_le2host(enext->length);
252 ebr_nblocks_max = ebr_nblocks_min;
253
254 if (enext->ptype == mbr_pt_unused || ebr_nblocks_min == 0)
255 break;
256
257 /* Verify next EBR does not overlap this EBR */
258 if (ebr_b0 < pebr_b0 + pebr_nblocks) {
259 rc = EIO;
260 goto error;
261 }
262
263 /* Verify next EBR does not extend beyond end of label */
264 if (ebr_b0 + ebr_nblocks_max > label->ablock0 + label->anblocks) {
265 rc = EIO;
266 goto error;
267 }
268 }
269
270 free(ebr);
271 return EOK;
272error:
273 /* Note that logical partitions need to be deleted by caller */
274 free(ebr);
[3faa03d]275 return rc;
276}
277
278static int mbr_create(service_id_t sid, label_t **rlabel)
279{
[603c1d1f]280 label_t *label = NULL;
281 mbr_br_block_t *mbr = NULL;
282 aoff64_t nblocks;
283 size_t bsize;
284 int i;
285 int rc;
286
287 rc = block_get_bsize(sid, &bsize);
288 if (rc != EOK) {
289 rc = EIO;
290 goto error;
291 }
292
293 rc = block_get_nblocks(sid, &nblocks);
294 if (rc != EOK) {
295 rc = EIO;
296 goto error;
297 }
298
299 mbr = calloc(1, bsize);
300 if (mbr == NULL) {
301 rc = ENOMEM;
302 goto error;
303 }
304
305 label = calloc(1, sizeof(label_t));
306 if (label == NULL)
307 return ENOMEM;
308
309 list_initialize(&label->parts);
[b7a4d06]310 list_initialize(&label->pri_parts);
311 list_initialize(&label->log_parts);
[603c1d1f]312
313 mbr->media_id = 0;
314 mbr->pad0 = 0;
315 for (i = 0; i < mbr_nprimary; i++)
316 mbr_unused_pte(&mbr->pte[i]);
317 mbr->signature = host2uint16_t_le(mbr_br_signature);
318
319 rc = block_write_direct(sid, mbr_ba, 1, mbr);
320 if (rc != EOK) {
321 rc = EIO;
322 goto error;
323 }
324
325 free(mbr);
326 mbr = NULL;
327
328 label->ops = &mbr_label_ops;
329 label->ltype = lt_mbr;
330 label->block_size = bsize;
331 label->svc_id = sid;
332 label->ablock0 = mbr_ablock0;
333 label->anblocks = nblocks - mbr_ablock0;
334 label->pri_entries = mbr_nprimary;
[c02d098]335 label->ext_part = NULL;
[603c1d1f]336
337 *rlabel = label;
[3faa03d]338 return EOK;
[603c1d1f]339error:
340 free(mbr);
341 free(label);
342 return rc;
[3faa03d]343}
344
345static void mbr_close(label_t *label)
346{
[603c1d1f]347 label_part_t *part;
348
[c02d098]349 if (label == NULL)
350 return;
351
[603c1d1f]352 part = mbr_part_first(label);
353 while (part != NULL) {
[b7a4d06]354 list_remove(&part->lparts);
355 if (link_used(&part->lpri))
356 list_remove(&part->lpri);
357 if (link_used(&part->llog))
358 list_remove(&part->llog);
[603c1d1f]359 free(part);
360
361 part = mbr_part_first(label);
362 }
363
[3faa03d]364 free(label);
365}
366
367static int mbr_destroy(label_t *label)
368{
[603c1d1f]369 mbr_br_block_t *mbr = NULL;
370 label_part_t *part;
371 int rc;
372
373 part = mbr_part_first(label);
374 if (part != NULL) {
375 rc = ENOTEMPTY;
376 goto error;
377 }
378
379 mbr = calloc(1, label->block_size);
380 if (mbr == NULL) {
381 rc = ENOMEM;
382 goto error;
383 }
384
385 rc = block_write_direct(label->svc_id, mbr_ba, 1, mbr);
386 if (rc != EOK) {
387 rc = EIO;
388 goto error;
389 }
390
391 free(mbr);
392 mbr = NULL;
393
394 free(label);
[3faa03d]395 return EOK;
[603c1d1f]396error:
397 free(mbr);
398 return rc;
[3faa03d]399}
400
[1626cd4]401static int mbr_get_info(label_t *label, label_info_t *linfo)
402{
403 memset(linfo, 0, sizeof(label_info_t));
404 linfo->ltype = lt_mbr;
[b7a4d06]405
406 /* We support extended partitions */
407 linfo->flags = lf_ext_supp;
408
409 /** Can create primary if there is a free slot */
410 if (list_count(&label->pri_parts) < mbr_nprimary)
411 linfo->flags |= lf_can_create_pri;
412 /* Can create extended if there is a free slot and no extended */
[c02d098]413 if ((linfo->flags & lf_can_create_pri) != 0 && label->ext_part == NULL)
[b7a4d06]414 linfo->flags |= lf_can_create_ext;
415 /* Can create logical if there is an extended partition */
[c02d098]416 if (label->ext_part != NULL)
[b7a4d06]417 linfo->flags |= lf_can_create_log;
418
[1626cd4]419 linfo->ablock0 = label->ablock0;
420 linfo->anblocks = label->anblocks;
[b7a4d06]421
[1626cd4]422 return EOK;
423}
424
[3faa03d]425static label_part_t *mbr_part_first(label_t *label)
426{
427 link_t *link;
428
429 link = list_first(&label->parts);
430 if (link == NULL)
431 return NULL;
432
[b7a4d06]433 return list_get_instance(link, label_part_t, lparts);
[3faa03d]434}
435
436static label_part_t *mbr_part_next(label_part_t *part)
437{
438 link_t *link;
439
[b7a4d06]440 link = list_next(&part->lparts, &part->label->parts);
[3faa03d]441 if (link == NULL)
442 return NULL;
443
[b7a4d06]444 return list_get_instance(link, label_part_t, lparts);
[3faa03d]445}
446
[c02d098]447static label_part_t *mbr_log_part_first(label_t *label)
448{
449 link_t *link;
450
451 link = list_first(&label->log_parts);
452 if (link == NULL)
453 return NULL;
454
455 return list_get_instance(link, label_part_t, llog);
456}
457
458static label_part_t *mbr_log_part_next(label_part_t *part)
459{
460 link_t *link;
461
462 link = list_next(&part->llog, &part->label->log_parts);
463 if (link == NULL)
464 return NULL;
465
466 return list_get_instance(link, label_part_t, llog);
467}
468
469static label_part_t *mbr_log_part_prev(label_part_t *part)
470{
471 link_t *link;
472
473 link = list_prev(&part->llog, &part->label->log_parts);
474 if (link == NULL)
475 return NULL;
476
477 return list_get_instance(link, label_part_t, llog);
478}
479
[b7a4d06]480#include <io/log.h>
[3faa03d]481static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
482{
[1626cd4]483 pinfo->index = part->index;
[3faa03d]484 pinfo->block0 = part->block0;
485 pinfo->nblocks = part->nblocks;
[b7a4d06]486
487 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_get_info: index=%d ptype=%d",
[f57ccb5]488 (int)part->index, (int)part->ptype.t.num);
[b7a4d06]489 if (link_used(&part->llog))
490 pinfo->pkind = lpk_logical;
[f57ccb5]491 else if (part->ptype.t.num == mbr_pt_extended)
[b7a4d06]492 pinfo->pkind = lpk_extended;
493 else
494 pinfo->pkind = lpk_primary;
[3faa03d]495}
496
497static int mbr_part_create(label_t *label, label_part_spec_t *pspec,
498 label_part_t **rpart)
499{
[6bc542b]500 label_part_t *part;
[c02d098]501 label_part_t *prev;
502 label_part_t *next;
[99c23405]503 mbr_pte_t pte;
504 int rc;
[6bc542b]505
[f57ccb5]506 if (pspec->ptype.fmt != lptf_num)
507 return EINVAL;
508
[6bc542b]509 part = calloc(1, sizeof(label_part_t));
510 if (part == NULL)
511 return ENOMEM;
512
[99c23405]513
514 /* XXX Check if index is used */
515
516 part->label = label;
[6bc542b]517 part->index = pspec->index;
518 part->block0 = pspec->block0;
519 part->nblocks = pspec->nblocks;
[c02d098]520 part->hdr_blocks = pspec->hdr_blocks;
[6bc542b]521
[b7a4d06]522 switch (pspec->pkind) {
523 case lpk_primary:
524 part->ptype = pspec->ptype;
525 break;
526 case lpk_extended:
[f57ccb5]527 part->ptype.fmt = lptf_num;
528 part->ptype.t.num = mbr_pt_extended;
529 if (pspec->ptype.t.num != 0) {
[b7a4d06]530 rc = EINVAL;
531 goto error;
532 }
[c02d098]533 if (label->ext_part != NULL) {
[b7a4d06]534 rc = EEXISTS;
535 goto error;
536 }
537 break;
538 case lpk_logical:
[c02d098]539 log_msg(LOG_DEFAULT, LVL_NOTE, "check index");
[b7a4d06]540 part->ptype = pspec->ptype;
541 if (pspec->index != 0) {
542 rc = EINVAL;
543 goto error;
544 }
545 break;
[99c23405]546 }
547
[b7a4d06]548 if (pspec->pkind != lpk_logical) {
549 /* Primary or extended partition */
550 /* XXX Verify index, block0, nblocks */
551
552 if (pspec->index < 1 || pspec->index > label->pri_entries) {
553 rc = EINVAL;
554 goto error;
555 }
556
[c02d098]557 if (pspec->hdr_blocks != 0) {
558 rc = EINVAL;
559 goto error;
560 }
561
[b7a4d06]562 rc = mbr_part_to_pte(part, &pte);
563 if (rc != EOK) {
564 rc = EINVAL;
565 goto error;
566 }
567
568 rc = mbr_pte_update(label, &pte, pspec->index - 1);
569 if (rc != EOK) {
570 rc = EIO;
571 goto error;
572 }
573
574 list_append(&part->lparts, &label->parts);
575 list_append(&part->lpri, &label->pri_parts);
576
577 if (pspec->pkind == lpk_extended)
[c02d098]578 label->ext_part = part;
[b7a4d06]579 } else {
580 /* Logical partition */
[c02d098]581
582 log_msg(LOG_DEFAULT, LVL_NOTE, "call mbr_log_part_insert");
583 rc = mbr_log_part_insert(label, part);
584 if (rc != EOK)
585 goto error;
586
587 log_msg(LOG_DEFAULT, LVL_NOTE, "call mbr_ebr_create");
588 /* Create EBR for new partition */
589 rc = mbr_ebr_create(label, part);
590 if (rc != EOK)
591 goto error;
592
593 prev = mbr_log_part_prev(part);
594 if (prev != NULL) {
595 log_msg(LOG_DEFAULT, LVL_NOTE, "update next");
596 /* Update 'next' PTE in EBR of previous partition */
597 rc = mbr_ebr_update_next(label, prev);
598 if (rc != EOK) {
599 log_msg(LOG_DEFAULT, LVL_NOTE, "failed to update next");
600 goto error;
601 }
602 } else {
603 log_msg(LOG_DEFAULT, LVL_NOTE, "relocate first EBR");
604 /* New partition is now the first one */
605 next = mbr_log_part_next(part);
606 if (next != NULL) {
607 /*
608 * Create new, relocated EBR for the former
609 * first partition
610 */
611 next->hdr_blocks = pspec->hdr_blocks;
612 rc = mbr_ebr_create(label, next);
613 if (rc != EOK)
614 goto error;
615 }
616 }
617
618 /* This also sets index for the new partition. */
619 mbr_update_log_indices(label);
[99c23405]620 }
621
[c02d098]622 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_create success");
[6bc542b]623 *rpart = part;
624 return EOK;
[99c23405]625error:
626 free(part);
627 return rc;
[3faa03d]628}
629
630static int mbr_part_destroy(label_part_t *part)
631{
[99c23405]632 mbr_pte_t pte;
[c02d098]633 label_part_t *prev;
[22747e8]634 label_part_t *next;
635 uint64_t ep_b0;
[99c23405]636 int rc;
637
[c02d098]638 if (link_used(&part->lpri)) {
639 /* Primary/extended partition */
[99c23405]640
[c02d098]641 /* Prepare unused partition table entry */
642 mbr_unused_pte(&pte);
[99c23405]643
[c02d098]644 /* Modify partition table */
645 rc = mbr_pte_update(part->label, &pte, part->index - 1);
646 if (rc != EOK)
647 return EIO;
648
649 /* If it was the extended partition, clear ext. part. pointer */
650 if (part == part->label->ext_part)
651 part->label->ext_part = NULL;
[b7a4d06]652
653 list_remove(&part->lpri);
[c02d098]654 } else {
655 /* Logical partition */
656
657 prev = mbr_log_part_prev(part);
658 if (prev != NULL) {
659 /* Update next link in previous EBR */
660 list_remove(&part->llog);
661
662 rc = mbr_ebr_update_next(part->label, prev);
663 if (rc != EOK) {
664 /* Roll back */
665 list_insert_after(&part->llog, &prev->llog);
666 return EIO;
667 }
[22747e8]668
669 /* Delete EBR */
670 rc = mbr_ebr_delete(part->label, part);
671 if (rc != EOK)
672 return EIO;
[c02d098]673 } else {
[22747e8]674 next = mbr_log_part_next(part);
[c02d098]675 list_remove(&part->llog);
676
[22747e8]677 if (next != NULL) {
678 /*
[83dd743]679 * Relocate next partition's EBR to the beginning
680 * of the extended partition. This also
681 * overwrites the EBR of the former first
682 * partition.
[22747e8]683 */
684
685 /* First block of extended partition */
686 ep_b0 = part->label->ext_part->block0;
687
688 next->hdr_blocks = next->block0 - ep_b0;
689
690 rc = mbr_ebr_create(part->label, next);
691 if (rc != EOK) {
692 list_prepend(&part->llog, &part->label->log_parts);
693 return EIO;
694 }
695 } else {
696 /* Delete EBR */
697 rc = mbr_ebr_delete(part->label, part);
698 if (rc != EOK)
699 return EIO;
700 }
701 }
[100b1d1]702
703 /* Update indices */
704 mbr_update_log_indices(part->label);
[c02d098]705 }
706
707 list_remove(&part->lparts);
[99c23405]708 free(part);
709 return EOK;
710}
711
[f57ccb5]712static int mbr_suggest_ptype(label_t *label, label_pcnt_t pcnt,
713 label_ptype_t *ptype)
714{
715 ptype->fmt = lptf_num;
716 ptype->t.num = 0;
717
718 switch (pcnt) {
719 case lpc_exfat:
720 ptype->t.num = mbr_pt_ms_advanced;
721 break;
722 case lpc_ext4:
723 ptype->t.num = mbr_pt_linux;
724 break;
725 case lpc_fat12_16:
726 ptype->t.num = mbr_pt_fat16_lba;
727 break;
728 case lpc_fat32:
729 ptype->t.num = mbr_pt_fat32_lba;
730 break;
731 case lpc_minix:
732 ptype->t.num = mbr_pt_minix;
733 break;
734 }
735
736 if (ptype->t.num == 0)
737 return EINVAL;
738
739 return EOK;
740}
741
742
[99c23405]743static void mbr_unused_pte(mbr_pte_t *pte)
744{
745 memset(pte, 0, sizeof(mbr_pte_t));
746}
747
748static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
749{
750 if ((part->block0 >> 32) != 0)
751 return EINVAL;
752 if ((part->nblocks >> 32) != 0)
753 return EINVAL;
[f57ccb5]754 if ((part->ptype.t.num >> 8) != 0)
[99c23405]755 return EINVAL;
756
[b7a4d06]757 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_to_pte: a0=%" PRIu64
758 " len=%" PRIu64 " ptype=%d", part->block0, part->nblocks,
[f57ccb5]759 (int)part->ptype.t.num);
[99c23405]760 memset(pte, 0, sizeof(mbr_pte_t));
[f57ccb5]761 pte->ptype = part->ptype.t.num;
[99c23405]762 pte->first_lba = host2uint32_t_le(part->block0);
763 pte->length = host2uint32_t_le(part->nblocks);
764 return EOK;
[3faa03d]765}
766
[1626cd4]767static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
[3faa03d]768{
769 label_part_t *part;
770 uint32_t block0;
771 uint32_t nblocks;
772
773 block0 = uint32_t_le2host(pte->first_lba);
774 nblocks = uint32_t_le2host(pte->length);
775
776 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
[b7a4d06]777 if (pte->ptype == mbr_pt_unused || nblocks == 0)
[3faa03d]778 return EOK;
779
780 part = calloc(1, sizeof(label_part_t));
781 if (part == NULL)
782 return ENOMEM;
783
[f57ccb5]784 part->ptype.fmt = lptf_num;
785 part->ptype.t.num = pte->ptype;
[1626cd4]786 part->index = index;
[3faa03d]787 part->block0 = block0;
788 part->nblocks = nblocks;
789
790 /*
791 * TODO: Verify
792 * - partition must reside on disk
793 * - partition must not overlap any other partition
794 */
795
796 part->label = label;
[b7a4d06]797 list_append(&part->lparts, &label->parts);
798 list_append(&part->lpri, &label->pri_parts);
799
800 if (pte->ptype == mbr_pt_extended)
[c02d098]801 label->ext_part = part;
802 return EOK;
803}
804
805static int mbr_pte_to_log_part(label_t *label, uint64_t ebr_b0,
806 mbr_pte_t *pte)
807{
808 label_part_t *part;
809 uint32_t block0;
810 uint32_t nblocks;
811 size_t nlparts;
812
813 block0 = ebr_b0 + uint32_t_le2host(pte->first_lba);
814 nblocks = uint32_t_le2host(pte->length);
815
816 if (pte->ptype == mbr_pt_unused || nblocks == 0)
817 return EOK;
818
819 part = calloc(1, sizeof(label_part_t));
820 if (part == NULL)
821 return ENOMEM;
822
823 nlparts = list_count(&label->log_parts);
824
[f57ccb5]825 part->ptype.fmt = lptf_num;
826 part->ptype.t.num = pte->ptype;
[c02d098]827 part->index = mbr_nprimary + 1 + nlparts;
828 part->block0 = block0;
829 part->nblocks = nblocks;
[100b1d1]830 part->hdr_blocks = block0 - ebr_b0;
[c02d098]831
832 part->label = label;
833 list_append(&part->lparts, &label->parts);
834 list_append(&part->llog, &label->log_parts);
835
[3faa03d]836 return EOK;
837}
[22747e8]838
[c02d098]839static void mbr_log_part_to_ptes(label_part_t *part, mbr_pte_t *pthis,
840 mbr_pte_t *pnext)
841{
842 label_part_t *next;
843 uint64_t ep_b0;
844 uint64_t totsize;
845
846 /* First block of extended partition */
847 ep_b0 = part->label->ext_part->block0;
848
849 assert(link_used(&part->llog));
850 assert(part->block0 >= ep_b0);
851 assert(part->hdr_blocks <= part->block0 - ep_b0);
852
853 /* 'This' EBR entry */
854 if (pthis != NULL) {
855 memset(pthis, 0, sizeof(mbr_pte_t));
[f57ccb5]856 pthis->ptype = part->ptype.t.num;
[c02d098]857 pthis->first_lba = host2uint32_t_le(part->hdr_blocks);
858 pthis->length = host2uint32_t_le(part->nblocks);
859 }
860
861 /* 'Next' EBR entry */
862 if (pnext != NULL) {
[22747e8]863 next = mbr_log_part_next(part);
[c02d098]864
865 memset(pnext, 0, sizeof(mbr_pte_t));
866 if (next != NULL) {
867 /* Total size of EBR + partition */
868 totsize = next->hdr_blocks + next->nblocks;
869
870 pnext->ptype = mbr_pt_extended;
871 pnext->first_lba = host2uint32_t_le(next->block0 -
872 next->hdr_blocks - ep_b0);
873 pnext->length = host2uint32_t_le(totsize);
874 }
875 }
876}
[3faa03d]877
[99c23405]878/** Update partition table entry at specified index.
879 *
880 * Replace partition entry at index @a index with the contents of
881 * @a pte.
882 */
883static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
884{
885 mbr_br_block_t *br;
886 int rc;
887
888 br = calloc(1, label->block_size);
889 if (br == NULL)
890 return ENOMEM;
891
[603c1d1f]892 rc = block_read_direct(label->svc_id, mbr_ba, 1, br);
[99c23405]893 if (rc != EOK) {
894 rc = EIO;
895 goto error;
896 }
897
898 br->pte[index] = *pte;
899
[603c1d1f]900 rc = block_write_direct(label->svc_id, mbr_ba, 1, br);
[99c23405]901 if (rc != EOK) {
902 rc = EIO;
903 goto error;
904 }
905
906 free(br);
907 return EOK;
908error:
909 free(br);
910 return rc;
911}
912
[c02d098]913/** Insert logical partition into logical partition list. */
914static int mbr_log_part_insert(label_t *label, label_part_t *part)
915{
916 label_part_t *cur;
917
918 cur = mbr_log_part_first(label);
919 while (cur != NULL) {
920 if (cur->block0 + cur->nblocks > part->block0)
921 break;
922 cur = mbr_log_part_next(part);
923 }
924
925 if (cur != NULL)
926 list_insert_before(&part->llog, &cur->llog);
927 else
928 list_append(&part->llog, &label->log_parts);
929
930 return EOK;
931}
932
933/** Create EBR for partition. */
934static int mbr_ebr_create(label_t *label, label_part_t *part)
935{
936 mbr_br_block_t *br;
937 uint64_t ba;
938 int rc;
939
940 br = calloc(1, label->block_size);
941 if (br == NULL)
942 return ENOMEM;
943
944 mbr_log_part_to_ptes(part, &br->pte[mbr_ebr_pte_this],
945 &br->pte[mbr_ebr_pte_next]);
946 br->signature = host2uint16_t_le(mbr_br_signature);
947
948 ba = part->block0 - part->hdr_blocks;
949
950 log_msg(LOG_DEFAULT, LVL_NOTE, "Write EBR to ba=%" PRIu64, ba);
951 rc = block_write_direct(label->svc_id, ba, 1, br);
952 if (rc != EOK) {
953 rc = EIO;
954 goto error;
955 }
956
957 free(br);
958 return EOK;
959error:
960 free(br);
961 return rc;
962}
963
964static int mbr_ebr_delete(label_t *label, label_part_t *part)
965{
966 mbr_br_block_t *br;
967 uint64_t ba;
968 int rc;
969
970 br = calloc(1, label->block_size);
971 if (br == NULL)
972 return ENOMEM;
973
974 ba = part->block0 - part->hdr_blocks;
975
976 rc = block_write_direct(label->svc_id, ba, 1, br);
977 if (rc != EOK) {
978 rc = EIO;
979 goto error;
980 }
981
982 free(br);
983 return EOK;
984error:
985 free(br);
986 return rc;
987}
988
989/** Update 'next' PTE in EBR of partition. */
990static int mbr_ebr_update_next(label_t *label, label_part_t *part)
991{
992 mbr_br_block_t *br;
993 uint64_t ba;
994 uint16_t sgn;
995 int rc;
996
997 ba = part->block0 - part->hdr_blocks;
998
999 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next ba=%" PRIu64,
1000 ba);
1001
1002 br = calloc(1, label->block_size);
1003 if (br == NULL)
1004 return ENOMEM;
1005
1006 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next read ba=%" PRIu64,
1007 ba);
1008
1009 rc = block_read_direct(label->svc_id, ba, 1, br);
1010 if (rc != EOK) {
1011 rc = EIO;
1012 goto error;
1013 }
1014
1015 /* Verify boot record signature */
1016 sgn = uint16_t_le2host(br->signature);
1017 if (sgn != mbr_br_signature) {
1018 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next signature error");
1019 rc = EIO;
1020 goto error;
1021 }
1022
1023 mbr_log_part_to_ptes(part, NULL, &br->pte[mbr_ebr_pte_next]);
1024
1025 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next write ba=%" PRIu64,
1026 ba);
1027
1028 rc = block_write_direct(label->svc_id, ba, 1, br);
1029 if (rc != EOK) {
1030 rc = EIO;
1031 goto error;
1032 }
1033
1034 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next success");
1035
1036 free(br);
1037 return EOK;
1038error:
1039 free(br);
1040 return rc;
1041}
1042
1043/** Update indices of logical partitions.
1044 *
1045 * Logical partition indices are unstable, i.e. they can change during
1046 * the lifetime of a logical partition. Since the index corresponds to the
1047 * position of the partition in order of block address, anytime a partition
1048 * is created or deleted, indices of all partitions at higher addresses
1049 * change.
1050 */
1051static void mbr_update_log_indices(label_t *label)
1052{
1053 label_part_t *part;
1054 int idx;
1055
1056 idx = mbr_nprimary + 1;
1057
1058 part = mbr_log_part_first(label);
1059 while (part != NULL) {
1060 part->index = idx++;
1061 part = mbr_log_part_next(part);
1062 }
1063}
1064
[3faa03d]1065/** @}
1066 */
Note: See TracBrowser for help on using the repository browser.