source: mainline/uspace/lib/label/src/gpt.c@ deacc58d

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

Break liblabel dependency on libblock.

  • Property mode set to 100644
File size: 21.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 GUID Partition Table label.
34 */
35
36#include <adt/checksum.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <mem.h>
40#include <stdint.h>
41#include <stdlib.h>
42#include <uuid.h>
43
44#include "std/mbr.h"
45#include "std/gpt.h"
46#include "gpt.h"
47
48static int gpt_open(label_bd_t *, label_t **);
49static int gpt_create(label_bd_t *, label_t **);
50static void gpt_close(label_t *);
51static int gpt_destroy(label_t *);
52static int gpt_get_info(label_t *, label_info_t *);
53static label_part_t *gpt_part_first(label_t *);
54static label_part_t *gpt_part_next(label_part_t *);
55static void gpt_part_get_info(label_part_t *, label_part_info_t *);
56static int gpt_part_create(label_t *, label_part_spec_t *, label_part_t **);
57static int gpt_part_destroy(label_part_t *);
58static int gpt_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
59
60static int gpt_check_free_idx(label_t *, int);
61static int gpt_check_free_range(label_t *, uint64_t, uint64_t);
62
63static void gpt_unused_pte(gpt_entry_t *);
64static int gpt_part_to_pte(label_part_t *, gpt_entry_t *);
65static int gpt_pte_to_part(label_t *, gpt_entry_t *, int);
66static int gpt_pte_update(label_t *, gpt_entry_t *, int);
67
68static int gpt_update_pt_crc(label_t *, uint32_t);
69static void gpt_hdr_compute_crc(gpt_header_t *, size_t);
70static int gpt_hdr_get_crc(gpt_header_t *, size_t, uint32_t *);
71
72static int gpt_pmbr_create(label_bd_t *, size_t, uint64_t);
73static int gpt_pmbr_destroy(label_bd_t *, size_t);
74
75const uint8_t efi_signature[8] = {
76 /* "EFI PART" in ASCII */
77 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
78};
79
80label_ops_t gpt_label_ops = {
81 .open = gpt_open,
82 .create = gpt_create,
83 .close = gpt_close,
84 .destroy = gpt_destroy,
85 .get_info = gpt_get_info,
86 .part_first = gpt_part_first,
87 .part_next = gpt_part_next,
88 .part_get_info = gpt_part_get_info,
89 .part_create = gpt_part_create,
90 .part_destroy = gpt_part_destroy,
91 .suggest_ptype = gpt_suggest_ptype
92};
93
94static int gpt_open(label_bd_t *bd, label_t **rlabel)
95{
96 label_t *label = NULL;
97 gpt_header_t *gpt_hdr[2];
98 gpt_entry_t *eptr;
99 uint8_t *etable[2];
100 size_t bsize;
101 uint32_t num_entries;
102 uint32_t esize;
103 uint32_t pt_blocks;
104 uint64_t ptba[2];
105 uint64_t h1ba;
106 uint32_t entry;
107 uint32_t pt_crc;
108 uint64_t ba_min, ba_max;
109 uint32_t hdr_size;
110 uint32_t hdr_crc;
111 int i, j;
112 int rc;
113
114 gpt_hdr[0] = NULL;
115 gpt_hdr[1] = NULL;
116 etable[0] = NULL;
117 etable[1] = NULL;
118
119 rc = bd->ops->get_bsize(bd->arg, &bsize);
120 if (rc != EOK) {
121 rc = EIO;
122 goto error;
123 }
124
125 if (bsize < 512 || (bsize % 512) != 0) {
126 rc = EINVAL;
127 goto error;
128 }
129
130 gpt_hdr[0] = calloc(1, bsize);
131 if (gpt_hdr[0] == NULL) {
132 rc = ENOMEM;
133 goto error;
134 }
135
136 gpt_hdr[1] = calloc(1, bsize);
137 if (gpt_hdr[1] == NULL) {
138 rc = ENOMEM;
139 goto error;
140 }
141
142 rc = bd->ops->read(bd->arg, gpt_hdr_ba, 1, gpt_hdr[0]);
143 if (rc != EOK) {
144 rc = EIO;
145 goto error;
146 }
147
148 h1ba = uint64_t_le2host(gpt_hdr[0]->alternate_lba);
149
150 rc = bd->ops->read(bd->arg, h1ba, 1, gpt_hdr[1]);
151 if (rc != EOK) {
152 rc = EIO;
153 goto error;
154 }
155
156 label = calloc(1, sizeof(label_t));
157 if (label == NULL)
158 return ENOMEM;
159
160 list_initialize(&label->parts);
161 list_initialize(&label->pri_parts);
162 list_initialize(&label->log_parts);
163
164 for (j = 0; j < 2; j++) {
165 for (i = 0; i < 8; ++i) {
166 if (gpt_hdr[j]->efi_signature[i] != efi_signature[i]) {
167 rc = EINVAL;
168 goto error;
169 }
170 }
171 }
172
173 if (uint32_t_le2host(gpt_hdr[0]->revision) !=
174 uint32_t_le2host(gpt_hdr[1]->revision)) {
175 rc = EINVAL;
176 goto error;
177 }
178
179 if (uint32_t_le2host(gpt_hdr[0]->header_size) !=
180 uint32_t_le2host(gpt_hdr[1]->header_size)) {
181 rc = EINVAL;
182 goto error;
183 }
184
185 hdr_size = uint32_t_le2host(gpt_hdr[0]->header_size);
186 if (hdr_size < sizeof(gpt_header_t) ||
187 hdr_size > bsize) {
188 rc = EINVAL;
189 goto error;
190 }
191
192 for (j = 0; j < 2; j++) {
193 rc = gpt_hdr_get_crc(gpt_hdr[j], hdr_size, &hdr_crc);
194 if (rc != EOK)
195 goto error;
196
197 if (uint32_t_le2host(gpt_hdr[j]->header_crc32) != hdr_crc) {
198 rc = EINVAL;
199 goto error;
200 }
201 }
202
203 if (uint64_t_le2host(gpt_hdr[0]->my_lba) != gpt_hdr_ba) {
204 rc = EINVAL;
205 goto error;
206 }
207
208 if (uint64_t_le2host(gpt_hdr[1]->my_lba) != h1ba) {
209 rc = EINVAL;
210 goto error;
211 }
212
213 if (uint64_t_le2host(gpt_hdr[1]->alternate_lba) != gpt_hdr_ba) {
214 rc = EINVAL;
215 goto error;
216 }
217
218 num_entries = uint32_t_le2host(gpt_hdr[0]->num_entries);
219 esize = uint32_t_le2host(gpt_hdr[0]->entry_size);
220 pt_blocks = (num_entries * esize + bsize - 1) / bsize;
221 ptba[0] = uint64_t_le2host(gpt_hdr[0]->entry_lba);
222 ptba[1] = uint64_t_le2host(gpt_hdr[1]->entry_lba);
223 ba_min = uint64_t_le2host(gpt_hdr[0]->first_usable_lba);
224 ba_max = uint64_t_le2host(gpt_hdr[0]->last_usable_lba);
225 pt_crc = uint32_t_le2host(gpt_hdr[0]->pe_array_crc32);
226
227 if (uint64_t_le2host(gpt_hdr[1]->first_usable_lba) != ba_min) {
228 rc = EINVAL;
229 goto error;
230 }
231
232 if (uint64_t_le2host(gpt_hdr[1]->last_usable_lba) != ba_max) {
233 rc = EINVAL;
234 goto error;
235 }
236
237 for (i = 0; i < 16; i++) {
238 if (gpt_hdr[1]->disk_guid[i] != gpt_hdr[0]->disk_guid[i]) {
239 rc = EINVAL;
240 goto error;
241 }
242 }
243
244 if (uint32_t_le2host(gpt_hdr[1]->num_entries) != num_entries) {
245 rc = EINVAL;
246 goto error;
247 }
248
249 if (uint32_t_le2host(gpt_hdr[1]->entry_size) != esize) {
250 rc = EINVAL;
251 goto error;
252 }
253
254 if (num_entries < 1) {
255 rc = EINVAL;
256 goto error;
257 }
258
259 if (esize < sizeof(gpt_entry_t)) {
260 rc = EINVAL;
261 goto error;
262 }
263
264 if (ba_max < ba_min) {
265 rc = EINVAL;
266 goto error;
267 }
268
269 /* Check fields in backup header for validity */
270
271 for (j = 0; j < 2; j++) {
272 etable[j] = calloc(1, pt_blocks * bsize);
273 if (etable[j] == NULL) {
274 rc = ENOMEM;
275 goto error;
276 }
277
278 rc = bd->ops->read(bd->arg, ptba[j], pt_blocks / 2, etable[j]);
279 if (rc != EOK) {
280 rc = EIO;
281 goto error;
282 }
283
284 if (compute_crc32(etable[j], num_entries * esize) != pt_crc) {
285 rc = EIO;
286 goto error;
287 }
288
289 }
290
291 for (entry = 0; entry < num_entries; entry++) {
292 eptr = (gpt_entry_t *)(etable[0] + entry * esize);
293 rc = gpt_pte_to_part(label, eptr, entry + 1);
294 if (rc != EOK)
295 goto error;
296 }
297
298 free(etable[0]);
299 etable[0] = NULL;
300 free(etable[1]);
301 etable[1] = NULL;
302 free(gpt_hdr[0]);
303 gpt_hdr[0] = NULL;
304 free(gpt_hdr[1]);
305 gpt_hdr[1] = NULL;
306
307 label->ops = &gpt_label_ops;
308 label->ltype = lt_gpt;
309 label->bd = *bd;
310 label->ablock0 = ba_min;
311 label->anblocks = ba_max - ba_min + 1;
312 label->pri_entries = num_entries;
313 label->block_size = bsize;
314
315 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
316 label->lt.gpt.hdr_ba[1] = h1ba;
317 label->lt.gpt.ptable_ba[0] = ptba[0];
318 label->lt.gpt.ptable_ba[1] = ptba[1];
319 label->lt.gpt.esize = esize;
320 label->lt.gpt.pt_blocks = pt_blocks;
321 label->lt.gpt.pt_crc = pt_crc;
322 label->lt.gpt.hdr_size = hdr_size;
323
324 *rlabel = label;
325 return EOK;
326error:
327 free(etable[0]);
328 free(etable[1]);
329 free(gpt_hdr[0]);
330 free(gpt_hdr[1]);
331 free(label);
332 return rc;
333}
334
335static int gpt_create(label_bd_t *bd, label_t **rlabel)
336{
337 label_t *label = NULL;
338 gpt_header_t *gpt_hdr = NULL;
339 uint8_t *etable = NULL;
340 size_t bsize;
341 uint32_t num_entries;
342 uint32_t esize;
343 uint64_t ptba[2];
344 uint64_t hdr_ba[2];
345 uint64_t pt_blocks;
346 uint64_t ba_min, ba_max;
347 aoff64_t nblocks;
348 uint64_t resv_blocks;
349 uint32_t pt_crc;
350 uuid_t disk_uuid;
351 int i, j;
352 int rc;
353
354 rc = bd->ops->get_bsize(bd->arg, &bsize);
355 if (rc != EOK) {
356 rc = EIO;
357 goto error;
358 }
359
360 if (bsize < 512 || (bsize % 512) != 0) {
361 rc = EINVAL;
362 goto error;
363 }
364
365 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
366 if (rc != EOK) {
367 rc = EIO;
368 goto error;
369 }
370
371 /* Number of blocks of a partition table */
372 pt_blocks = gpt_ptable_min_size / bsize;
373 /* Minimum number of reserved (not allocatable) blocks */
374 resv_blocks = 3 + 2 * pt_blocks;
375
376 if (nblocks <= resv_blocks) {
377 rc = ENOSPC;
378 goto error;
379 }
380
381 rc = gpt_pmbr_create(bd, bsize, nblocks);
382 if (rc != EOK) {
383 rc = EIO;
384 goto error;
385 }
386
387 uuid_generate(&disk_uuid);
388
389 hdr_ba[0] = gpt_hdr_ba;
390 hdr_ba[1] = nblocks - 1;
391 ptba[0] = 2;
392 ptba[1] = nblocks - 1 - pt_blocks;
393 ba_min = ptba[0] + pt_blocks;
394 ba_max = ptba[1] - 1;
395 esize = sizeof(gpt_entry_t);
396
397 num_entries = pt_blocks * bsize / sizeof(gpt_entry_t);
398
399 for (i = 0; i < 2; i++) {
400 etable = calloc(1, pt_blocks * bsize);
401 if (etable == NULL) {
402 rc = ENOMEM;
403 goto error;
404 }
405
406 rc = bd->ops->write(bd->arg, ptba[i], pt_blocks, etable);
407 if (rc != EOK) {
408 rc = EIO;
409 goto error;
410 }
411
412 pt_crc = compute_crc32((uint8_t *)etable,
413 num_entries * esize);
414
415 free(etable);
416 etable = NULL;
417
418 gpt_hdr = calloc(1, bsize);
419 if (gpt_hdr == NULL) {
420 rc = ENOMEM;
421 goto error;
422 }
423
424 for (j = 0; j < 8; ++j)
425 gpt_hdr->efi_signature[j] = efi_signature[j];
426 gpt_hdr->revision = host2uint32_t_le(gpt_revision);
427 gpt_hdr->header_size = host2uint32_t_le(sizeof(gpt_header_t));
428 gpt_hdr->header_crc32 = 0;
429 gpt_hdr->my_lba = host2uint64_t_le(hdr_ba[i]);
430 gpt_hdr->alternate_lba = host2uint64_t_le(hdr_ba[1 - i]);
431 gpt_hdr->first_usable_lba = host2uint64_t_le(ba_min);
432 gpt_hdr->last_usable_lba = host2uint64_t_le(ba_max);
433 uuid_encode(&disk_uuid, gpt_hdr->disk_guid);
434 gpt_hdr->entry_lba = host2uint64_t_le(ptba[i]);
435 gpt_hdr->num_entries = host2uint32_t_le(num_entries);
436 gpt_hdr->entry_size = host2uint32_t_le(esize);
437 gpt_hdr->pe_array_crc32 = pt_crc;
438
439 gpt_hdr_compute_crc(gpt_hdr, sizeof(gpt_header_t));
440
441 rc = bd->ops->write(bd->arg, hdr_ba[i], 1, gpt_hdr);
442 if (rc != EOK) {
443 rc = EIO;
444 goto error;
445 }
446
447 free(gpt_hdr);
448 gpt_hdr = NULL;
449 }
450
451 label = calloc(1, sizeof(label_t));
452 if (label == NULL)
453 return ENOMEM;
454
455 list_initialize(&label->parts);
456 list_initialize(&label->pri_parts);
457 list_initialize(&label->log_parts);
458
459 label->ops = &gpt_label_ops;
460 label->ltype = lt_gpt;
461 label->bd = *bd;
462 label->ablock0 = ba_min;
463 label->anblocks = ba_max - ba_min + 1;
464 label->pri_entries = num_entries;
465 label->block_size = bsize;
466
467 label->lt.gpt.hdr_ba[0] = hdr_ba[0];
468 label->lt.gpt.hdr_ba[1] = hdr_ba[1];
469 label->lt.gpt.ptable_ba[0] = ptba[0];
470 label->lt.gpt.ptable_ba[1] = ptba[1];
471 label->lt.gpt.esize = esize;
472 label->lt.gpt.pt_blocks = pt_blocks;
473 label->lt.gpt.pt_crc = pt_crc;
474 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
475
476 *rlabel = label;
477 return EOK;
478error:
479 free(etable);
480 free(gpt_hdr);
481 free(label);
482 return rc;
483}
484
485static void gpt_close(label_t *label)
486{
487 label_part_t *part;
488
489 part = gpt_part_first(label);
490 while (part != NULL) {
491 list_remove(&part->lparts);
492 list_remove(&part->lpri);
493 free(part);
494 part = gpt_part_first(label);
495 }
496
497 free(label);
498}
499
500static int gpt_destroy(label_t *label)
501{
502 gpt_header_t *gpt_hdr = NULL;
503 uint8_t *etable = NULL;
504 label_part_t *part;
505 int i;
506 int rc;
507
508 part = gpt_part_first(label);
509 if (part != NULL) {
510 rc = ENOTEMPTY;
511 goto error;
512 }
513
514 for (i = 0; i < 2; i++) {
515 gpt_hdr = calloc(1, label->block_size);
516 if (gpt_hdr == NULL) {
517 rc = ENOMEM;
518 goto error;
519 }
520
521 rc = label->bd.ops->write(label->bd.arg, label->lt.gpt.hdr_ba[i],
522 1, gpt_hdr);
523 if (rc != EOK) {
524 rc = EIO;
525 goto error;
526 }
527
528 free(gpt_hdr);
529 gpt_hdr = NULL;
530
531 etable = calloc(1, label->lt.gpt.pt_blocks *
532 label->block_size);
533 if (etable == NULL) {
534 rc = ENOMEM;
535 goto error;
536 }
537
538 rc = label->bd.ops->write(label->bd.arg,
539 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
540 etable);
541 if (rc != EOK) {
542 rc = EIO;
543 goto error;
544 }
545
546 free(etable);
547 etable = 0;
548 }
549
550 rc = gpt_pmbr_destroy(&label->bd, label->block_size);
551 if (rc != EOK)
552 goto error;
553
554 free(label);
555 return EOK;
556error:
557 return rc;
558}
559
560static bool gpt_can_create_pri(label_t *label)
561{
562 return list_count(&label->parts) < (size_t)label->pri_entries;
563}
564
565static bool gpt_can_delete_part(label_t *label)
566{
567 return list_count(&label->parts) > 0;
568}
569
570static int gpt_get_info(label_t *label, label_info_t *linfo)
571{
572 memset(linfo, 0, sizeof(label_info_t));
573 linfo->ltype = lt_gpt;
574 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
575 if (gpt_can_create_pri(label))
576 linfo->flags = linfo->flags | lf_can_create_pri;
577 if (gpt_can_delete_part(label))
578 linfo->flags = linfo->flags | lf_can_delete_part;
579 linfo->ablock0 = label->ablock0;
580 linfo->anblocks = label->anblocks;
581 return EOK;
582}
583
584static label_part_t *gpt_part_first(label_t *label)
585{
586 link_t *link;
587
588 link = list_first(&label->parts);
589 if (link == NULL)
590 return NULL;
591
592 return list_get_instance(link, label_part_t, lparts);
593}
594
595static label_part_t *gpt_part_next(label_part_t *part)
596{
597 link_t *link;
598
599 link = list_next(&part->lparts, &part->label->parts);
600 if (link == NULL)
601 return NULL;
602
603 return list_get_instance(link, label_part_t, lparts);
604}
605
606static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
607{
608 pinfo->index = part->index;
609 pinfo->pkind = lpk_primary;
610 pinfo->block0 = part->block0;
611 pinfo->nblocks = part->nblocks;
612}
613
614static int gpt_part_create(label_t *label, label_part_spec_t *pspec,
615 label_part_t **rpart)
616{
617 label_part_t *part;
618 gpt_entry_t pte;
619 int rc;
620
621 part = calloc(1, sizeof(label_part_t));
622 if (part == NULL) {
623 rc = ENOMEM;
624 goto error;
625 }
626
627 /* Verify index is within bounds and free */
628 rc = gpt_check_free_idx(label, pspec->index);
629 if (rc != EOK) {
630 rc = EINVAL;
631 goto error;
632 }
633
634 /* Verify range is within bounds and free */
635 rc = gpt_check_free_range(label, pspec->block0, pspec->nblocks);
636 if (rc != EOK) {
637 rc = EINVAL;
638 goto error;
639 }
640
641 /* GPT only has primary partitions */
642 if (pspec->pkind != lpk_primary) {
643 rc = EINVAL;
644 goto error;
645 }
646
647 /* Partition type must be in UUID format */
648 if (pspec->ptype.fmt != lptf_uuid) {
649 rc = EINVAL;
650 goto error;
651 }
652
653 /* XXX Check if index is used */
654
655 part->label = label;
656 part->index = pspec->index;
657 part->block0 = pspec->block0;
658 part->nblocks = pspec->nblocks;
659 part->ptype = pspec->ptype;
660 uuid_generate(&part->part_uuid);
661
662 /* Prepare partition table entry */
663 rc = gpt_part_to_pte(part, &pte);
664 if (rc != EOK) {
665 rc = EINVAL;
666 goto error;
667 }
668
669 /* Modify partition tables */
670 rc = gpt_pte_update(label, &pte, pspec->index - 1);
671 if (rc != EOK) {
672 rc = EIO;
673 goto error;
674 }
675
676 list_append(&part->lparts, &label->parts);
677 list_append(&part->lpri, &label->pri_parts);
678
679 *rpart = part;
680 return EOK;
681error:
682 free(part);
683 return rc;
684}
685
686static int gpt_part_destroy(label_part_t *part)
687{
688 gpt_entry_t pte;
689 int rc;
690
691 /* Prepare unused partition table entry */
692 gpt_unused_pte(&pte);
693
694 /* Modify partition tables */
695 rc = gpt_pte_update(part->label, &pte, part->index - 1);
696 if (rc != EOK)
697 return EIO;
698
699 list_remove(&part->lparts);
700 list_remove(&part->lpri);
701 free(part);
702 return EOK;
703}
704
705static int gpt_suggest_ptype(label_t *label, label_pcnt_t pcnt,
706 label_ptype_t *ptype)
707{
708 const char *ptid;
709 int rc;
710
711 ptid = NULL;
712
713 switch (pcnt) {
714 case lpc_fat12_16:
715 case lpc_exfat:
716 case lpc_fat32:
717 ptid = GPT_MS_BASIC_DATA;
718 break;
719 case lpc_ext4:
720 ptid = GPT_LINUX_FS_DATA;
721 break;
722 case lpc_minix:
723 ptid = GPT_MINIX_FAKE;
724 break;
725 }
726
727 if (ptid == NULL)
728 return EINVAL;
729
730 ptype->fmt = lptf_uuid;
731 rc = uuid_parse(ptid, &ptype->t.uuid, NULL);
732 assert(rc == EOK);
733
734 return EOK;
735}
736
737/** Verify that the specified index is valid and free. */
738static int gpt_check_free_idx(label_t *label, int index)
739{
740 label_part_t *part;
741
742 if (index < 1 || index > label->pri_entries)
743 return EINVAL;
744
745 part = gpt_part_first(label);
746 while (part != NULL) {
747 if (part->index == index)
748 return EEXIST;
749 part = gpt_part_next(part);
750 }
751
752 return EOK;
753}
754
755/** Determine if two block address ranges overlap. */
756static bool gpt_overlap(uint64_t a0, uint64_t an, uint64_t b0, uint64_t bn)
757{
758 return !(a0 + an <= b0 || b0 + bn <= a0);
759}
760
761static int gpt_check_free_range(label_t *label, uint64_t block0,
762 uint64_t nblocks)
763{
764 label_part_t *part;
765
766 if (block0 < label->ablock0)
767 return EINVAL;
768 if (block0 + nblocks > label->ablock0 + label->anblocks)
769 return EINVAL;
770
771 part = gpt_part_first(label);
772 while (part != NULL) {
773 if (gpt_overlap(block0, nblocks, part->block0, part->nblocks))
774 return EEXIST;
775 part = gpt_part_next(part);
776 }
777
778 return EOK;
779}
780
781static void gpt_unused_pte(gpt_entry_t *pte)
782{
783 memset(pte, 0, sizeof(gpt_entry_t));
784}
785
786static int gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
787{
788 uint64_t eblock;
789
790 eblock = part->block0 + part->nblocks - 1;
791 if (eblock < part->block0)
792 return EINVAL;
793
794 memset(pte, 0, sizeof(gpt_entry_t));
795 uuid_encode(&part->ptype.t.uuid, pte->part_type);
796 uuid_encode(&part->part_uuid, pte->part_id);
797 pte->start_lba = host2uint64_t_le(part->block0);
798 pte->end_lba = host2uint64_t_le(eblock);
799// pte->attributes
800// pte->part_name
801 return EOK;
802}
803
804static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
805{
806 label_part_t *part;
807 bool present;
808 uint64_t b0, b1;
809 int i;
810
811 present = false;
812 for (i = 0; i < 8; i++)
813 if (pte->part_type[i] != 0x00)
814 present = true;
815
816 if (!present)
817 return EOK;
818
819 b0 = uint64_t_le2host(pte->start_lba);
820 b1 = uint64_t_le2host(pte->end_lba);
821 if (b1 <= b0)
822 return EINVAL;
823
824 part = calloc(1, sizeof(label_part_t));
825 if (part == NULL)
826 return ENOMEM;
827
828 part->index = index;
829 part->block0 = b0;
830 part->nblocks = b1 - b0 + 1;
831 part->ptype.fmt = lptf_uuid;
832 uuid_decode(pte->part_type, &part->ptype.t.uuid);
833 uuid_decode(pte->part_id, &part->part_uuid);
834
835 part->label = label;
836 list_append(&part->lparts, &label->parts);
837 list_append(&part->lpri, &label->pri_parts);
838 return EOK;
839}
840
841/** Update partition table entry at specified index.
842 *
843 * Replace partition entry at index @a index with the contents of
844 * @a pte.
845 */
846static int gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
847{
848 size_t pos;
849 uint64_t ba;
850 uint64_t nblocks;
851 size_t ptbytes;
852 uint8_t *buf;
853 gpt_entry_t *e;
854 uint32_t crc;
855 int i;
856 int rc;
857
858 /* Byte offset of partition entry */
859 pos = index * label->lt.gpt.esize;
860 /* Number of bytes in partition table */
861 ptbytes = label->pri_entries * label->lt.gpt.esize;
862
863 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
864 if (buf == NULL)
865 return ENOMEM;
866
867 /* For both partition tables: read, modify, write */
868 for (i = 0; i < 2; i++) {
869 ba = label->lt.gpt.ptable_ba[i];
870 nblocks = label->lt.gpt.pt_blocks;
871
872 rc = label->bd.ops->read(label->bd.arg, ba, nblocks, buf);
873 if (rc != EOK) {
874 rc = EIO;
875 goto error;
876 }
877
878 crc = compute_crc32(buf, ptbytes);
879 if (crc != label->lt.gpt.pt_crc) {
880 /* Corruption detected */
881 rc = EIO;
882 goto error;
883 }
884
885 /* Replace single entry */
886 e = (gpt_entry_t *)(&buf[pos]);
887 *e = *pte;
888
889 rc = label->bd.ops->write(label->bd.arg, ba, nblocks, buf);
890 if (rc != EOK) {
891 rc = EIO;
892 goto error;
893 }
894
895 crc = compute_crc32(buf, ptbytes);
896 rc = gpt_update_pt_crc(label, crc);
897 if (rc != EOK) {
898 rc = EIO;
899 goto error;
900 }
901 }
902
903 label->lt.gpt.pt_crc = crc;
904 free(buf);
905 return EOK;
906error:
907 free(buf);
908 return rc;
909}
910
911static int gpt_update_pt_crc(label_t *label, uint32_t crc)
912{
913 gpt_header_t *gpt_hdr;
914 int rc;
915 int i;
916
917 gpt_hdr = calloc(1, label->block_size);
918 if (gpt_hdr == NULL) {
919 rc = ENOMEM;
920 goto exit;
921 }
922
923 for (i = 0; i < 2; i++) {
924 rc = label->bd.ops->read(label->bd.arg,
925 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
926 if (rc != EOK) {
927 rc = EIO;
928 goto exit;
929 }
930
931 gpt_hdr->pe_array_crc32 = host2uint32_t_le(crc);
932 gpt_hdr_compute_crc(gpt_hdr, label->lt.gpt.hdr_size);
933
934 rc = label->bd.ops->write(label->bd.arg,
935 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
936 if (rc != EOK) {
937 rc = EIO;
938 goto exit;
939 }
940 }
941
942 rc = EOK;
943
944exit:
945 free(gpt_hdr);
946 return rc;
947}
948
949static void gpt_hdr_compute_crc(gpt_header_t *hdr, size_t hdr_size)
950{
951 uint32_t crc;
952
953 hdr->header_crc32 = 0;
954 crc = compute_crc32((uint8_t *)hdr, hdr_size);
955 hdr->header_crc32 = crc;
956}
957
958static int gpt_hdr_get_crc(gpt_header_t *hdr, size_t hdr_size, uint32_t *crc)
959{
960 gpt_header_t *c;
961
962 c = calloc(1, hdr_size);
963 if (c == NULL)
964 return ENOMEM;
965
966 memcpy(c, hdr, hdr_size);
967 c->header_crc32 = 0;
968 *crc = compute_crc32((uint8_t *)c, hdr_size);
969 free(c);
970
971 return EOK;
972}
973
974/** Create GPT Protective MBR */
975static int gpt_pmbr_create(label_bd_t *bd, size_t bsize, uint64_t nblocks)
976{
977 mbr_br_block_t *pmbr = NULL;
978 uint64_t pmbr_nb;
979 int rc;
980
981 pmbr = calloc(1, bsize);
982 if (pmbr == NULL) {
983 rc = ENOMEM;
984 goto error;
985 }
986
987 pmbr_nb = nblocks - gpt_hdr_ba;
988
989 pmbr->pte[0].ptype = mbr_pt_gpt_protect;
990 pmbr->pte[0].first_lba = gpt_hdr_ba;
991
992 if (pmbr_nb <= UINT32_MAX)
993 pmbr->pte[0].length = host2uint32_t_le((uint32_t)pmbr_nb);
994 else
995 pmbr->pte[0].length = host2uint32_t_le(UINT32_MAX);
996
997 pmbr->signature = host2uint16_t_le(mbr_br_signature);
998
999 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
1000 if (rc != EOK) {
1001 rc = EIO;
1002 goto error;
1003 }
1004
1005 free(pmbr);
1006 return EOK;
1007error:
1008 free(pmbr);
1009 return rc;
1010}
1011
1012/** Destroy GPT Protective MBR */
1013static int gpt_pmbr_destroy(label_bd_t *bd, size_t bsize)
1014{
1015 mbr_br_block_t *pmbr = NULL;
1016 int rc;
1017
1018 pmbr = calloc(1, bsize);
1019 if (pmbr == NULL) {
1020 rc = ENOMEM;
1021 goto error;
1022 }
1023
1024 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
1025 if (rc != EOK) {
1026 rc = EIO;
1027 goto error;
1028 }
1029
1030 free(pmbr);
1031 return EOK;
1032error:
1033 free(pmbr);
1034 return rc;
1035}
1036
1037/** @}
1038 */
Note: See TracBrowser for help on using the repository browser.