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

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

GPT should check alt. header block address for sanity before trying to read it.

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