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
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 GUID Partition Table label.
34 */
35
[bf7ddde]36#include <adt/checksum.h>
[3faa03d]37#include <byteorder.h>
38#include <errno.h>
[1626cd4]39#include <mem.h>
[cffa82aa]40#include <stdint.h>
[3faa03d]41#include <stdlib.h>
[70815a24]42#include <uuid.h>
[3faa03d]43
[cffa82aa]44#include "std/mbr.h"
[3faa03d]45#include "std/gpt.h"
46#include "gpt.h"
47
[deacc58d]48static int gpt_open(label_bd_t *, label_t **);
49static int gpt_create(label_bd_t *, label_t **);
[3faa03d]50static void gpt_close(label_t *);
51static int gpt_destroy(label_t *);
[1626cd4]52static int gpt_get_info(label_t *, label_info_t *);
[3faa03d]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 *);
[f57ccb5]58static int gpt_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
[3faa03d]59
[d8513177]60static int gpt_check_free_idx(label_t *, int);
61static int gpt_check_free_range(label_t *, uint64_t, uint64_t);
62
[99c23405]63static void gpt_unused_pte(gpt_entry_t *);
64static int gpt_part_to_pte(label_part_t *, gpt_entry_t *);
[1626cd4]65static int gpt_pte_to_part(label_t *, gpt_entry_t *, int);
[99c23405]66static int gpt_pte_update(label_t *, gpt_entry_t *, int);
[3faa03d]67
[bf7ddde]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
[deacc58d]72static int gpt_pmbr_create(label_bd_t *, size_t, uint64_t);
73static int gpt_pmbr_destroy(label_bd_t *, size_t);
[cffa82aa]74
[3faa03d]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,
[1626cd4]85 .get_info = gpt_get_info,
[3faa03d]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,
[f57ccb5]90 .part_destroy = gpt_part_destroy,
91 .suggest_ptype = gpt_suggest_ptype
[3faa03d]92};
93
[deacc58d]94static int gpt_open(label_bd_t *bd, label_t **rlabel)
[3faa03d]95{
96 label_t *label = NULL;
[99c23405]97 gpt_header_t *gpt_hdr[2];
[3faa03d]98 gpt_entry_t *eptr;
[bf7ddde]99 uint8_t *etable[2];
[3faa03d]100 size_t bsize;
101 uint32_t num_entries;
102 uint32_t esize;
[bf7ddde]103 uint32_t pt_blocks;
[99c23405]104 uint64_t ptba[2];
105 uint64_t h1ba;
[3faa03d]106 uint32_t entry;
[bf7ddde]107 uint32_t pt_crc;
[1626cd4]108 uint64_t ba_min, ba_max;
[bf7ddde]109 uint32_t hdr_size;
110 uint32_t hdr_crc;
[99c23405]111 int i, j;
[3faa03d]112 int rc;
113
[99c23405]114 gpt_hdr[0] = NULL;
115 gpt_hdr[1] = NULL;
[bf7ddde]116 etable[0] = NULL;
117 etable[1] = NULL;
[99c23405]118
[deacc58d]119 rc = bd->ops->get_bsize(bd->arg, &bsize);
[3faa03d]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
[99c23405]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) {
[3faa03d]138 rc = ENOMEM;
139 goto error;
140 }
141
[deacc58d]142 rc = bd->ops->read(bd->arg, gpt_hdr_ba, 1, gpt_hdr[0]);
[99c23405]143 if (rc != EOK) {
144 rc = EIO;
145 goto error;
146 }
147
148 h1ba = uint64_t_le2host(gpt_hdr[0]->alternate_lba);
149
[deacc58d]150 rc = bd->ops->read(bd->arg, h1ba, 1, gpt_hdr[1]);
[3faa03d]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);
[b7a4d06]161 list_initialize(&label->pri_parts);
162 list_initialize(&label->log_parts);
[3faa03d]163
[99c23405]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 }
[3faa03d]170 }
171 }
172
[bf7ddde]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
[99c23405]218 num_entries = uint32_t_le2host(gpt_hdr[0]->num_entries);
219 esize = uint32_t_le2host(gpt_hdr[0]->entry_size);
[bf7ddde]220 pt_blocks = (num_entries * esize + bsize - 1) / bsize;
[99c23405]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);
[bf7ddde]225 pt_crc = uint32_t_le2host(gpt_hdr[0]->pe_array_crc32);
[3faa03d]226
[bf7ddde]227 if (uint64_t_le2host(gpt_hdr[1]->first_usable_lba) != ba_min) {
[3faa03d]228 rc = EINVAL;
229 goto error;
230 }
231
[bf7ddde]232 if (uint64_t_le2host(gpt_hdr[1]->last_usable_lba) != ba_max) {
[3faa03d]233 rc = EINVAL;
234 goto error;
235 }
236
[bf7ddde]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) {
[1626cd4]245 rc = EINVAL;
246 goto error;
247 }
248
[bf7ddde]249 if (uint32_t_le2host(gpt_hdr[1]->entry_size) != esize) {
250 rc = EINVAL;
[3faa03d]251 goto error;
252 }
253
[bf7ddde]254 if (num_entries < 1) {
255 rc = EINVAL;
[3faa03d]256 goto error;
257 }
258
[bf7ddde]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
[deacc58d]278 rc = bd->ops->read(bd->arg, ptba[j], pt_blocks / 2, etable[j]);
[bf7ddde]279 if (rc != EOK) {
280 rc = EIO;
[3faa03d]281 goto error;
[bf7ddde]282 }
283
284 if (compute_crc32(etable[j], num_entries * esize) != pt_crc) {
285 rc = EIO;
286 goto error;
287 }
288
[9624c35]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;
[3faa03d]296 }
297
[bf7ddde]298 free(etable[0]);
299 etable[0] = NULL;
300 free(etable[1]);
301 etable[1] = NULL;
[99c23405]302 free(gpt_hdr[0]);
303 gpt_hdr[0] = NULL;
304 free(gpt_hdr[1]);
305 gpt_hdr[1] = NULL;
[3faa03d]306
307 label->ops = &gpt_label_ops;
308 label->ltype = lt_gpt;
[deacc58d]309 label->bd = *bd;
[1626cd4]310 label->ablock0 = ba_min;
311 label->anblocks = ba_max - ba_min + 1;
[99c23405]312 label->pri_entries = num_entries;
313 label->block_size = bsize;
314
[603c1d1f]315 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
316 label->lt.gpt.hdr_ba[1] = h1ba;
[99c23405]317 label->lt.gpt.ptable_ba[0] = ptba[0];
318 label->lt.gpt.ptable_ba[1] = ptba[1];
319 label->lt.gpt.esize = esize;
[bf7ddde]320 label->lt.gpt.pt_blocks = pt_blocks;
321 label->lt.gpt.pt_crc = pt_crc;
322 label->lt.gpt.hdr_size = hdr_size;
[99c23405]323
[3faa03d]324 *rlabel = label;
325 return EOK;
326error:
[bf7ddde]327 free(etable[0]);
328 free(etable[1]);
[99c23405]329 free(gpt_hdr[0]);
330 free(gpt_hdr[1]);
[3faa03d]331 free(label);
332 return rc;
333}
334
[deacc58d]335static int gpt_create(label_bd_t *bd, label_t **rlabel)
[3faa03d]336{
[603c1d1f]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;
[bf7ddde]349 uint32_t pt_crc;
[70815a24]350 uuid_t disk_uuid;
[603c1d1f]351 int i, j;
352 int rc;
353
[deacc58d]354 rc = bd->ops->get_bsize(bd->arg, &bsize);
[603c1d1f]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
[deacc58d]365 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
[603c1d1f]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
[deacc58d]381 rc = gpt_pmbr_create(bd, bsize, nblocks);
[cffa82aa]382 if (rc != EOK) {
383 rc = EIO;
384 goto error;
385 }
386
[0bde8523]387 uuid_generate(&disk_uuid);
388
[603c1d1f]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++) {
[bf7ddde]400 etable = calloc(1, pt_blocks * bsize);
401 if (etable == NULL) {
402 rc = ENOMEM;
403 goto error;
404 }
405
[deacc58d]406 rc = bd->ops->write(bd->arg, ptba[i], pt_blocks, etable);
[bf7ddde]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
[603c1d1f]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));
[bf7ddde]428 gpt_hdr->header_crc32 = 0;
[603c1d1f]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);
[70815a24]433 uuid_encode(&disk_uuid, gpt_hdr->disk_guid);
[603c1d1f]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);
[bf7ddde]437 gpt_hdr->pe_array_crc32 = pt_crc;
438
439 gpt_hdr_compute_crc(gpt_hdr, sizeof(gpt_header_t));
[603c1d1f]440
[deacc58d]441 rc = bd->ops->write(bd->arg, hdr_ba[i], 1, gpt_hdr);
[603c1d1f]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);
[b7a4d06]456 list_initialize(&label->pri_parts);
457 list_initialize(&label->log_parts);
[603c1d1f]458
459 label->ops = &gpt_label_ops;
460 label->ltype = lt_gpt;
[deacc58d]461 label->bd = *bd;
[603c1d1f]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;
[bf7ddde]472 label->lt.gpt.pt_blocks = pt_blocks;
[3feeab2]473 label->lt.gpt.pt_crc = pt_crc;
[bf7ddde]474 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
[603c1d1f]475
476 *rlabel = label;
[3faa03d]477 return EOK;
[603c1d1f]478error:
479 free(etable);
480 free(gpt_hdr);
481 free(label);
482 return rc;
[3faa03d]483}
484
485static void gpt_close(label_t *label)
486{
[603c1d1f]487 label_part_t *part;
488
489 part = gpt_part_first(label);
490 while (part != NULL) {
[b7a4d06]491 list_remove(&part->lparts);
492 list_remove(&part->lpri);
[603c1d1f]493 free(part);
494 part = gpt_part_first(label);
495 }
496
[3faa03d]497 free(label);
498}
499
500static int gpt_destroy(label_t *label)
501{
[603c1d1f]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
[deacc58d]521 rc = label->bd.ops->write(label->bd.arg, label->lt.gpt.hdr_ba[i],
[603c1d1f]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
[bf7ddde]531 etable = calloc(1, label->lt.gpt.pt_blocks *
532 label->block_size);
[603c1d1f]533 if (etable == NULL) {
534 rc = ENOMEM;
535 goto error;
536 }
537
[deacc58d]538 rc = label->bd.ops->write(label->bd.arg,
[bf7ddde]539 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
540 etable);
[603c1d1f]541 if (rc != EOK) {
542 rc = EIO;
543 goto error;
544 }
545
546 free(etable);
547 etable = 0;
548 }
549
[deacc58d]550 rc = gpt_pmbr_destroy(&label->bd, label->block_size);
[cffa82aa]551 if (rc != EOK)
552 goto error;
553
[603c1d1f]554 free(label);
[3faa03d]555 return EOK;
[603c1d1f]556error:
557 return rc;
[3faa03d]558}
559
[b7a4d06]560static bool gpt_can_create_pri(label_t *label)
561{
562 return list_count(&label->parts) < (size_t)label->pri_entries;
563}
564
[edebb4a1]565static bool gpt_can_delete_part(label_t *label)
566{
567 return list_count(&label->parts) > 0;
568}
569
[1626cd4]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;
[f57ccb5]574 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
[b7a4d06]575 if (gpt_can_create_pri(label))
576 linfo->flags = linfo->flags | lf_can_create_pri;
[edebb4a1]577 if (gpt_can_delete_part(label))
578 linfo->flags = linfo->flags | lf_can_delete_part;
[1626cd4]579 linfo->ablock0 = label->ablock0;
580 linfo->anblocks = label->anblocks;
581 return EOK;
582}
583
[3faa03d]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
[b7a4d06]592 return list_get_instance(link, label_part_t, lparts);
[3faa03d]593}
594
595static label_part_t *gpt_part_next(label_part_t *part)
596{
597 link_t *link;
598
[b7a4d06]599 link = list_next(&part->lparts, &part->label->parts);
[3faa03d]600 if (link == NULL)
601 return NULL;
602
[b7a4d06]603 return list_get_instance(link, label_part_t, lparts);
[3faa03d]604}
605
606static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
607{
[1626cd4]608 pinfo->index = part->index;
[b7a4d06]609 pinfo->pkind = lpk_primary;
[3faa03d]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{
[6bc542b]617 label_part_t *part;
[99c23405]618 gpt_entry_t pte;
619 int rc;
[6bc542b]620
621 part = calloc(1, sizeof(label_part_t));
[99c23405]622 if (part == NULL) {
623 rc = ENOMEM;
624 goto error;
625 }
[6bc542b]626
[d8513177]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 }
[6bc542b]633
[d8513177]634 /* Verify range is within bounds and free */
635 rc = gpt_check_free_range(label, pspec->block0, pspec->nblocks);
636 if (rc != EOK) {
[99c23405]637 rc = EINVAL;
638 goto error;
639 }
640
[b7a4d06]641 /* GPT only has primary partitions */
642 if (pspec->pkind != lpk_primary) {
643 rc = EINVAL;
644 goto error;
645 }
646
[f57ccb5]647 /* Partition type must be in UUID format */
648 if (pspec->ptype.fmt != lptf_uuid) {
649 rc = EINVAL;
650 goto error;
651 }
652
[99c23405]653 /* XXX Check if index is used */
654
655 part->label = label;
[6bc542b]656 part->index = pspec->index;
657 part->block0 = pspec->block0;
658 part->nblocks = pspec->nblocks;
[99c23405]659 part->ptype = pspec->ptype;
[70815a24]660 uuid_generate(&part->part_uuid);
[99c23405]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 }
[6bc542b]668
[99c23405]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 }
[6bc542b]675
[b7a4d06]676 list_append(&part->lparts, &label->parts);
677 list_append(&part->lpri, &label->pri_parts);
[6bc542b]678
679 *rpart = part;
680 return EOK;
[99c23405]681error:
682 free(part);
683 return rc;
[3faa03d]684}
685
686static int gpt_part_destroy(label_part_t *part)
687{
[99c23405]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
[b7a4d06]699 list_remove(&part->lparts);
700 list_remove(&part->lpri);
[99c23405]701 free(part);
702 return EOK;
703}
704
[f57ccb5]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
[d8513177]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
[99c23405]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));
[f57ccb5]795 uuid_encode(&part->ptype.t.uuid, pte->part_type);
[70815a24]796 uuid_encode(&part->part_uuid, pte->part_id);
[99c23405]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;
[3faa03d]802}
803
[1626cd4]804static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
[3faa03d]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
[722bb5a]824 part = calloc(1, sizeof(label_part_t));
825 if (part == NULL)
826 return ENOMEM;
827
[1626cd4]828 part->index = index;
[3faa03d]829 part->block0 = b0;
830 part->nblocks = b1 - b0 + 1;
[f57ccb5]831 part->ptype.fmt = lptf_uuid;
832 uuid_decode(pte->part_type, &part->ptype.t.uuid);
[70815a24]833 uuid_decode(pte->part_id, &part->part_uuid);
[3faa03d]834
835 part->label = label;
[b7a4d06]836 list_append(&part->lparts, &label->parts);
837 list_append(&part->lpri, &label->pri_parts);
[3faa03d]838 return EOK;
839}
840
[99c23405]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;
[bf7ddde]850 uint64_t nblocks;
851 size_t ptbytes;
[99c23405]852 uint8_t *buf;
853 gpt_entry_t *e;
[bf7ddde]854 uint32_t crc;
[99c23405]855 int i;
856 int rc;
857
[bf7ddde]858 /* Byte offset of partition entry */
[99c23405]859 pos = index * label->lt.gpt.esize;
[bf7ddde]860 /* Number of bytes in partition table */
861 ptbytes = label->pri_entries * label->lt.gpt.esize;
[99c23405]862
[bf7ddde]863 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
[99c23405]864 if (buf == NULL)
865 return ENOMEM;
866
867 /* For both partition tables: read, modify, write */
868 for (i = 0; i < 2; i++) {
[bf7ddde]869 ba = label->lt.gpt.ptable_ba[i];
870 nblocks = label->lt.gpt.pt_blocks;
[99c23405]871
[deacc58d]872 rc = label->bd.ops->read(label->bd.arg, ba, nblocks, buf);
[99c23405]873 if (rc != EOK) {
874 rc = EIO;
875 goto error;
876 }
877
[bf7ddde]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
[99c23405]885 /* Replace single entry */
[bf7ddde]886 e = (gpt_entry_t *)(&buf[pos]);
[99c23405]887 *e = *pte;
888
[deacc58d]889 rc = label->bd.ops->write(label->bd.arg, ba, nblocks, buf);
[bf7ddde]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);
[99c23405]897 if (rc != EOK) {
898 rc = EIO;
899 goto error;
900 }
901 }
902
[3feeab2]903 label->lt.gpt.pt_crc = crc;
[99c23405]904 free(buf);
905 return EOK;
906error:
907 free(buf);
908 return rc;
909}
910
[bf7ddde]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;
[6a66923]920 goto exit;
[bf7ddde]921 }
922
923 for (i = 0; i < 2; i++) {
[deacc58d]924 rc = label->bd.ops->read(label->bd.arg,
[bf7ddde]925 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
926 if (rc != EOK) {
927 rc = EIO;
[6a66923]928 goto exit;
[bf7ddde]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
[deacc58d]934 rc = label->bd.ops->write(label->bd.arg,
[bf7ddde]935 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
936 if (rc != EOK) {
937 rc = EIO;
[6a66923]938 goto exit;
[bf7ddde]939 }
940 }
[deacc58d]941
[6a66923]942 rc = EOK;
[deacc58d]943
[6a66923]944exit:
[bf7ddde]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
[eed70f1]962 c = calloc(1, hdr_size);
[bf7ddde]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
[cffa82aa]974/** Create GPT Protective MBR */
[deacc58d]975static int gpt_pmbr_create(label_bd_t *bd, size_t bsize, uint64_t nblocks)
[cffa82aa]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
[deacc58d]999 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
[cffa82aa]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 */
[deacc58d]1013static int gpt_pmbr_destroy(label_bd_t *bd, size_t bsize)
[cffa82aa]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
[deacc58d]1024 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
[cffa82aa]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
[3faa03d]1037/** @}
1038 */
Note: See TracBrowser for help on using the repository browser.