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

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

Implement GPT protective MBR.

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