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

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

Modifying mount point for a partition.

  • Property mode set to 100644
File size: 22.3 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
[b7fd2a0]48static errno_t gpt_open(label_bd_t *, label_t **);
49static errno_t gpt_create(label_bd_t *, label_t **);
[3faa03d]50static void gpt_close(label_t *);
[b7fd2a0]51static errno_t gpt_destroy(label_t *);
52static errno_t 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 *);
[b7fd2a0]56static errno_t gpt_part_create(label_t *, label_part_spec_t *, label_part_t **);
57static errno_t gpt_part_destroy(label_part_t *);
58static errno_t gpt_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
[3faa03d]59
[b7fd2a0]60static errno_t gpt_check_free_idx(label_t *, int);
61static errno_t gpt_check_free_range(label_t *, uint64_t, uint64_t);
[d8513177]62
[99c23405]63static void gpt_unused_pte(gpt_entry_t *);
[b7fd2a0]64static errno_t gpt_part_to_pte(label_part_t *, gpt_entry_t *);
65static errno_t gpt_pte_to_part(label_t *, gpt_entry_t *, int);
66static errno_t gpt_pte_update(label_t *, gpt_entry_t *, int);
[3faa03d]67
[b7fd2a0]68static errno_t gpt_update_pt_crc(label_t *, uint32_t);
[bf7ddde]69static void gpt_hdr_compute_crc(gpt_header_t *, size_t);
[b7fd2a0]70static errno_t gpt_hdr_get_crc(gpt_header_t *, size_t, uint32_t *);
[bf7ddde]71
[b7fd2a0]72static errno_t gpt_pmbr_create(label_bd_t *, size_t, uint64_t);
73static errno_t 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
[b7fd2a0]94static errno_t 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;
[b33d140]101 aoff64_t nblocks;
[3faa03d]102 uint32_t num_entries;
103 uint32_t esize;
[bf7ddde]104 uint32_t pt_blocks;
[99c23405]105 uint64_t ptba[2];
106 uint64_t h1ba;
[3faa03d]107 uint32_t entry;
[bf7ddde]108 uint32_t pt_crc;
[1626cd4]109 uint64_t ba_min, ba_max;
[bf7ddde]110 uint32_t hdr_size;
111 uint32_t hdr_crc;
[99c23405]112 int i, j;
[b7fd2a0]113 errno_t rc;
[3faa03d]114
[99c23405]115 gpt_hdr[0] = NULL;
116 gpt_hdr[1] = NULL;
[bf7ddde]117 etable[0] = NULL;
118 etable[1] = NULL;
[99c23405]119
[deacc58d]120 rc = bd->ops->get_bsize(bd->arg, &bsize);
[3faa03d]121 if (rc != EOK) {
122 rc = EIO;
123 goto error;
124 }
125
[b33d140]126 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
127 if (rc != EOK) {
128 rc = EIO;
129 goto error;
130 }
131
[3faa03d]132 if (bsize < 512 || (bsize % 512) != 0) {
133 rc = EINVAL;
134 goto error;
135 }
136
[99c23405]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) {
[3faa03d]145 rc = ENOMEM;
146 goto error;
147 }
148
[deacc58d]149 rc = bd->ops->read(bd->arg, gpt_hdr_ba, 1, gpt_hdr[0]);
[99c23405]150 if (rc != EOK) {
151 rc = EIO;
152 goto error;
153 }
154
155 h1ba = uint64_t_le2host(gpt_hdr[0]->alternate_lba);
156
[b33d140]157 if (h1ba >= nblocks) {
158 rc = EINVAL;
159 goto error;
160 }
161
[deacc58d]162 rc = bd->ops->read(bd->arg, h1ba, 1, gpt_hdr[1]);
[3faa03d]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);
[b7a4d06]173 list_initialize(&label->pri_parts);
174 list_initialize(&label->log_parts);
[3faa03d]175
[99c23405]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 }
[3faa03d]182 }
183 }
184
[bf7ddde]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) {
[1433ecda]210 rc = EINVAL;
[bf7ddde]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
[99c23405]230 num_entries = uint32_t_le2host(gpt_hdr[0]->num_entries);
231 esize = uint32_t_le2host(gpt_hdr[0]->entry_size);
[bf7ddde]232 pt_blocks = (num_entries * esize + bsize - 1) / bsize;
[99c23405]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);
[bf7ddde]237 pt_crc = uint32_t_le2host(gpt_hdr[0]->pe_array_crc32);
[3faa03d]238
[bf7ddde]239 if (uint64_t_le2host(gpt_hdr[1]->first_usable_lba) != ba_min) {
[3faa03d]240 rc = EINVAL;
241 goto error;
242 }
243
[bf7ddde]244 if (uint64_t_le2host(gpt_hdr[1]->last_usable_lba) != ba_max) {
[3faa03d]245 rc = EINVAL;
246 goto error;
247 }
248
[bf7ddde]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) {
[1626cd4]257 rc = EINVAL;
258 goto error;
259 }
260
[bf7ddde]261 if (uint32_t_le2host(gpt_hdr[1]->entry_size) != esize) {
262 rc = EINVAL;
[3faa03d]263 goto error;
264 }
265
[bf7ddde]266 if (num_entries < 1) {
267 rc = EINVAL;
[3faa03d]268 goto error;
269 }
270
[bf7ddde]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
[deacc58d]290 rc = bd->ops->read(bd->arg, ptba[j], pt_blocks / 2, etable[j]);
[bf7ddde]291 if (rc != EOK) {
292 rc = EIO;
[3faa03d]293 goto error;
[bf7ddde]294 }
295
296 if (compute_crc32(etable[j], num_entries * esize) != pt_crc) {
297 rc = EIO;
298 goto error;
299 }
300
[9624c35]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;
[3faa03d]308 }
309
[bf7ddde]310 free(etable[0]);
311 etable[0] = NULL;
312 free(etable[1]);
313 etable[1] = NULL;
[99c23405]314 free(gpt_hdr[0]);
315 gpt_hdr[0] = NULL;
316 free(gpt_hdr[1]);
317 gpt_hdr[1] = NULL;
[3faa03d]318
319 label->ops = &gpt_label_ops;
320 label->ltype = lt_gpt;
[deacc58d]321 label->bd = *bd;
[1626cd4]322 label->ablock0 = ba_min;
323 label->anblocks = ba_max - ba_min + 1;
[99c23405]324 label->pri_entries = num_entries;
325 label->block_size = bsize;
326
[603c1d1f]327 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
328 label->lt.gpt.hdr_ba[1] = h1ba;
[99c23405]329 label->lt.gpt.ptable_ba[0] = ptba[0];
330 label->lt.gpt.ptable_ba[1] = ptba[1];
331 label->lt.gpt.esize = esize;
[bf7ddde]332 label->lt.gpt.pt_blocks = pt_blocks;
333 label->lt.gpt.pt_crc = pt_crc;
334 label->lt.gpt.hdr_size = hdr_size;
[99c23405]335
[3faa03d]336 *rlabel = label;
337 return EOK;
338error:
[bf7ddde]339 free(etable[0]);
340 free(etable[1]);
[99c23405]341 free(gpt_hdr[0]);
342 free(gpt_hdr[1]);
[3faa03d]343 free(label);
344 return rc;
345}
346
[b7fd2a0]347static errno_t gpt_create(label_bd_t *bd, label_t **rlabel)
[3faa03d]348{
[603c1d1f]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;
[bf7ddde]361 uint32_t pt_crc;
[70815a24]362 uuid_t disk_uuid;
[603c1d1f]363 int i, j;
[b7fd2a0]364 errno_t rc;
[603c1d1f]365
[deacc58d]366 rc = bd->ops->get_bsize(bd->arg, &bsize);
[603c1d1f]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
[deacc58d]377 rc = bd->ops->get_nblocks(bd->arg, &nblocks);
[603c1d1f]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
[deacc58d]393 rc = gpt_pmbr_create(bd, bsize, nblocks);
[cffa82aa]394 if (rc != EOK) {
395 rc = EIO;
396 goto error;
397 }
398
[0bde8523]399 uuid_generate(&disk_uuid);
400
[603c1d1f]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++) {
[bf7ddde]412 etable = calloc(1, pt_blocks * bsize);
413 if (etable == NULL) {
414 rc = ENOMEM;
415 goto error;
416 }
417
[deacc58d]418 rc = bd->ops->write(bd->arg, ptba[i], pt_blocks, etable);
[bf7ddde]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
[603c1d1f]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));
[bf7ddde]440 gpt_hdr->header_crc32 = 0;
[603c1d1f]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);
[70815a24]445 uuid_encode(&disk_uuid, gpt_hdr->disk_guid);
[603c1d1f]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);
[bf7ddde]449 gpt_hdr->pe_array_crc32 = pt_crc;
450
451 gpt_hdr_compute_crc(gpt_hdr, sizeof(gpt_header_t));
[603c1d1f]452
[deacc58d]453 rc = bd->ops->write(bd->arg, hdr_ba[i], 1, gpt_hdr);
[603c1d1f]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);
[b7a4d06]468 list_initialize(&label->pri_parts);
469 list_initialize(&label->log_parts);
[603c1d1f]470
471 label->ops = &gpt_label_ops;
472 label->ltype = lt_gpt;
[deacc58d]473 label->bd = *bd;
[603c1d1f]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;
[bf7ddde]484 label->lt.gpt.pt_blocks = pt_blocks;
[3feeab2]485 label->lt.gpt.pt_crc = pt_crc;
[bf7ddde]486 label->lt.gpt.hdr_size = sizeof(gpt_header_t);
[603c1d1f]487
488 *rlabel = label;
[3faa03d]489 return EOK;
[603c1d1f]490error:
491 free(etable);
492 free(gpt_hdr);
493 free(label);
494 return rc;
[3faa03d]495}
496
497static void gpt_close(label_t *label)
498{
[603c1d1f]499 label_part_t *part;
500
501 part = gpt_part_first(label);
502 while (part != NULL) {
[b7a4d06]503 list_remove(&part->lparts);
504 list_remove(&part->lpri);
[603c1d1f]505 free(part);
506 part = gpt_part_first(label);
507 }
508
[3faa03d]509 free(label);
510}
511
[b7fd2a0]512static errno_t gpt_destroy(label_t *label)
[3faa03d]513{
[603c1d1f]514 gpt_header_t *gpt_hdr = NULL;
515 uint8_t *etable = NULL;
516 label_part_t *part;
517 int i;
[b7fd2a0]518 errno_t rc;
[603c1d1f]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
[deacc58d]533 rc = label->bd.ops->write(label->bd.arg, label->lt.gpt.hdr_ba[i],
[603c1d1f]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
[bf7ddde]543 etable = calloc(1, label->lt.gpt.pt_blocks *
544 label->block_size);
[603c1d1f]545 if (etable == NULL) {
546 rc = ENOMEM;
547 goto error;
548 }
549
[deacc58d]550 rc = label->bd.ops->write(label->bd.arg,
[bf7ddde]551 label->lt.gpt.ptable_ba[i], label->lt.gpt.pt_blocks,
552 etable);
[603c1d1f]553 if (rc != EOK) {
554 rc = EIO;
555 goto error;
556 }
557
558 free(etable);
559 etable = 0;
560 }
561
[deacc58d]562 rc = gpt_pmbr_destroy(&label->bd, label->block_size);
[cffa82aa]563 if (rc != EOK)
564 goto error;
565
[603c1d1f]566 free(label);
[3faa03d]567 return EOK;
[603c1d1f]568error:
569 return rc;
[3faa03d]570}
571
[b7a4d06]572static bool gpt_can_create_pri(label_t *label)
573{
574 return list_count(&label->parts) < (size_t)label->pri_entries;
575}
576
[edebb4a1]577static bool gpt_can_delete_part(label_t *label)
578{
579 return list_count(&label->parts) > 0;
580}
581
[2d78d88]582static bool gpt_can_modify_part(label_t *label)
583{
584 return list_count(&label->parts) > 0;
585}
586
[b7fd2a0]587static errno_t gpt_get_info(label_t *label, label_info_t *linfo)
[1626cd4]588{
589 memset(linfo, 0, sizeof(label_info_t));
590 linfo->ltype = lt_gpt;
[f57ccb5]591 linfo->flags = lf_ptype_uuid; /* Partition type is in UUID format */
[b7a4d06]592 if (gpt_can_create_pri(label))
593 linfo->flags = linfo->flags | lf_can_create_pri;
[edebb4a1]594 if (gpt_can_delete_part(label))
595 linfo->flags = linfo->flags | lf_can_delete_part;
[2d78d88]596 if (gpt_can_modify_part(label))
597 linfo->flags = linfo->flags | lf_can_modify_part;
[1626cd4]598 linfo->ablock0 = label->ablock0;
599 linfo->anblocks = label->anblocks;
600 return EOK;
601}
602
[3faa03d]603static label_part_t *gpt_part_first(label_t *label)
604{
605 link_t *link;
606
607 link = list_first(&label->parts);
608 if (link == NULL)
609 return NULL;
610
[b7a4d06]611 return list_get_instance(link, label_part_t, lparts);
[3faa03d]612}
613
614static label_part_t *gpt_part_next(label_part_t *part)
615{
616 link_t *link;
617
[b7a4d06]618 link = list_next(&part->lparts, &part->label->parts);
[3faa03d]619 if (link == NULL)
620 return NULL;
621
[b7a4d06]622 return list_get_instance(link, label_part_t, lparts);
[3faa03d]623}
624
625static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
626{
[1626cd4]627 pinfo->index = part->index;
[b7a4d06]628 pinfo->pkind = lpk_primary;
[3faa03d]629 pinfo->block0 = part->block0;
630 pinfo->nblocks = part->nblocks;
631}
632
[b7fd2a0]633static errno_t gpt_part_create(label_t *label, label_part_spec_t *pspec,
[3faa03d]634 label_part_t **rpart)
635{
[6bc542b]636 label_part_t *part;
[99c23405]637 gpt_entry_t pte;
[b7fd2a0]638 errno_t rc;
[6bc542b]639
640 part = calloc(1, sizeof(label_part_t));
[99c23405]641 if (part == NULL) {
642 rc = ENOMEM;
643 goto error;
644 }
[6bc542b]645
[d8513177]646 /* Verify index is within bounds and free */
647 rc = gpt_check_free_idx(label, pspec->index);
648 if (rc != EOK) {
649 rc = EINVAL;
650 goto error;
651 }
[6bc542b]652
[d8513177]653 /* Verify range is within bounds and free */
654 rc = gpt_check_free_range(label, pspec->block0, pspec->nblocks);
655 if (rc != EOK) {
[99c23405]656 rc = EINVAL;
657 goto error;
658 }
659
[b7a4d06]660 /* GPT only has primary partitions */
661 if (pspec->pkind != lpk_primary) {
662 rc = EINVAL;
663 goto error;
664 }
665
[f57ccb5]666 /* Partition type must be in UUID format */
667 if (pspec->ptype.fmt != lptf_uuid) {
668 rc = EINVAL;
669 goto error;
670 }
671
[99c23405]672 /* XXX Check if index is used */
673
674 part->label = label;
[6bc542b]675 part->index = pspec->index;
676 part->block0 = pspec->block0;
677 part->nblocks = pspec->nblocks;
[99c23405]678 part->ptype = pspec->ptype;
[70815a24]679 uuid_generate(&part->part_uuid);
[99c23405]680
681 /* Prepare partition table entry */
682 rc = gpt_part_to_pte(part, &pte);
683 if (rc != EOK) {
684 rc = EINVAL;
685 goto error;
686 }
[6bc542b]687
[99c23405]688 /* Modify partition tables */
689 rc = gpt_pte_update(label, &pte, pspec->index - 1);
690 if (rc != EOK) {
691 rc = EIO;
692 goto error;
693 }
[6bc542b]694
[b7a4d06]695 list_append(&part->lparts, &label->parts);
696 list_append(&part->lpri, &label->pri_parts);
[6bc542b]697
698 *rpart = part;
699 return EOK;
[99c23405]700error:
701 free(part);
702 return rc;
[3faa03d]703}
704
[b7fd2a0]705static errno_t gpt_part_destroy(label_part_t *part)
[3faa03d]706{
[99c23405]707 gpt_entry_t pte;
[b7fd2a0]708 errno_t rc;
[99c23405]709
710 /* Prepare unused partition table entry */
711 gpt_unused_pte(&pte);
712
713 /* Modify partition tables */
714 rc = gpt_pte_update(part->label, &pte, part->index - 1);
715 if (rc != EOK)
716 return EIO;
717
[b7a4d06]718 list_remove(&part->lparts);
719 list_remove(&part->lpri);
[99c23405]720 free(part);
721 return EOK;
722}
723
[b7fd2a0]724static errno_t gpt_suggest_ptype(label_t *label, label_pcnt_t pcnt,
[f57ccb5]725 label_ptype_t *ptype)
726{
727 const char *ptid;
[b7fd2a0]728 errno_t rc;
[f57ccb5]729
730 ptid = NULL;
731
732 switch (pcnt) {
733 case lpc_fat12_16:
734 case lpc_exfat:
735 case lpc_fat32:
736 ptid = GPT_MS_BASIC_DATA;
737 break;
738 case lpc_ext4:
739 ptid = GPT_LINUX_FS_DATA;
740 break;
741 case lpc_minix:
742 ptid = GPT_MINIX_FAKE;
743 break;
744 }
745
746 if (ptid == NULL)
747 return EINVAL;
748
749 ptype->fmt = lptf_uuid;
750 rc = uuid_parse(ptid, &ptype->t.uuid, NULL);
751 assert(rc == EOK);
752
753 return EOK;
754}
755
[d8513177]756/** Verify that the specified index is valid and free. */
[b7fd2a0]757static errno_t gpt_check_free_idx(label_t *label, int index)
[d8513177]758{
759 label_part_t *part;
760
761 if (index < 1 || index > label->pri_entries)
762 return EINVAL;
763
764 part = gpt_part_first(label);
765 while (part != NULL) {
766 if (part->index == index)
767 return EEXIST;
768 part = gpt_part_next(part);
769 }
770
771 return EOK;
772}
773
774/** Determine if two block address ranges overlap. */
775static bool gpt_overlap(uint64_t a0, uint64_t an, uint64_t b0, uint64_t bn)
776{
777 return !(a0 + an <= b0 || b0 + bn <= a0);
778}
779
[b7fd2a0]780static errno_t gpt_check_free_range(label_t *label, uint64_t block0,
[d8513177]781 uint64_t nblocks)
782{
783 label_part_t *part;
784
785 if (block0 < label->ablock0)
786 return EINVAL;
787 if (block0 + nblocks > label->ablock0 + label->anblocks)
788 return EINVAL;
789
790 part = gpt_part_first(label);
791 while (part != NULL) {
792 if (gpt_overlap(block0, nblocks, part->block0, part->nblocks))
793 return EEXIST;
794 part = gpt_part_next(part);
795 }
796
797 return EOK;
798}
799
[99c23405]800static void gpt_unused_pte(gpt_entry_t *pte)
801{
802 memset(pte, 0, sizeof(gpt_entry_t));
803}
804
[b7fd2a0]805static errno_t gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
[99c23405]806{
807 uint64_t eblock;
808
809 eblock = part->block0 + part->nblocks - 1;
810 if (eblock < part->block0)
811 return EINVAL;
812
813 memset(pte, 0, sizeof(gpt_entry_t));
[f57ccb5]814 uuid_encode(&part->ptype.t.uuid, pte->part_type);
[70815a24]815 uuid_encode(&part->part_uuid, pte->part_id);
[99c23405]816 pte->start_lba = host2uint64_t_le(part->block0);
817 pte->end_lba = host2uint64_t_le(eblock);
[3fafe5e0]818 //pte->attributes
819 //pte->part_name
[99c23405]820 return EOK;
[3faa03d]821}
822
[b7fd2a0]823static errno_t gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
[3faa03d]824{
825 label_part_t *part;
826 bool present;
827 uint64_t b0, b1;
828 int i;
829
830 present = false;
831 for (i = 0; i < 8; i++)
832 if (pte->part_type[i] != 0x00)
833 present = true;
834
835 if (!present)
836 return EOK;
837
838 b0 = uint64_t_le2host(pte->start_lba);
839 b1 = uint64_t_le2host(pte->end_lba);
840 if (b1 <= b0)
841 return EINVAL;
842
[722bb5a]843 part = calloc(1, sizeof(label_part_t));
844 if (part == NULL)
845 return ENOMEM;
846
[1626cd4]847 part->index = index;
[3faa03d]848 part->block0 = b0;
849 part->nblocks = b1 - b0 + 1;
[f57ccb5]850 part->ptype.fmt = lptf_uuid;
851 uuid_decode(pte->part_type, &part->ptype.t.uuid);
[70815a24]852 uuid_decode(pte->part_id, &part->part_uuid);
[3faa03d]853
854 part->label = label;
[b7a4d06]855 list_append(&part->lparts, &label->parts);
856 list_append(&part->lpri, &label->pri_parts);
[3faa03d]857 return EOK;
858}
859
[99c23405]860/** Update partition table entry at specified index.
861 *
862 * Replace partition entry at index @a index with the contents of
863 * @a pte.
864 */
[b7fd2a0]865static errno_t gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
[99c23405]866{
867 size_t pos;
868 uint64_t ba;
[bf7ddde]869 uint64_t nblocks;
870 size_t ptbytes;
[99c23405]871 uint8_t *buf;
872 gpt_entry_t *e;
[bf7ddde]873 uint32_t crc;
[99c23405]874 int i;
[b7fd2a0]875 errno_t rc;
[99c23405]876
[bf7ddde]877 /* Byte offset of partition entry */
[99c23405]878 pos = index * label->lt.gpt.esize;
[bf7ddde]879 /* Number of bytes in partition table */
880 ptbytes = label->pri_entries * label->lt.gpt.esize;
[99c23405]881
[bf7ddde]882 buf = calloc(1, label->block_size * label->lt.gpt.pt_blocks);
[99c23405]883 if (buf == NULL)
884 return ENOMEM;
885
886 /* For both partition tables: read, modify, write */
887 for (i = 0; i < 2; i++) {
[bf7ddde]888 ba = label->lt.gpt.ptable_ba[i];
889 nblocks = label->lt.gpt.pt_blocks;
[99c23405]890
[deacc58d]891 rc = label->bd.ops->read(label->bd.arg, ba, nblocks, buf);
[99c23405]892 if (rc != EOK) {
893 rc = EIO;
894 goto error;
895 }
896
[bf7ddde]897 crc = compute_crc32(buf, ptbytes);
898 if (crc != label->lt.gpt.pt_crc) {
899 /* Corruption detected */
900 rc = EIO;
901 goto error;
902 }
903
[99c23405]904 /* Replace single entry */
[bf7ddde]905 e = (gpt_entry_t *)(&buf[pos]);
[99c23405]906 *e = *pte;
907
[deacc58d]908 rc = label->bd.ops->write(label->bd.arg, ba, nblocks, buf);
[bf7ddde]909 if (rc != EOK) {
910 rc = EIO;
911 goto error;
912 }
913
914 crc = compute_crc32(buf, ptbytes);
915 rc = gpt_update_pt_crc(label, crc);
[99c23405]916 if (rc != EOK) {
917 rc = EIO;
918 goto error;
919 }
920 }
921
[3feeab2]922 label->lt.gpt.pt_crc = crc;
[99c23405]923 free(buf);
924 return EOK;
925error:
926 free(buf);
927 return rc;
928}
929
[b7fd2a0]930static errno_t gpt_update_pt_crc(label_t *label, uint32_t crc)
[bf7ddde]931{
932 gpt_header_t *gpt_hdr;
[b7fd2a0]933 errno_t rc;
[bf7ddde]934 int i;
935
936 gpt_hdr = calloc(1, label->block_size);
937 if (gpt_hdr == NULL) {
938 rc = ENOMEM;
[6a66923]939 goto exit;
[bf7ddde]940 }
941
942 for (i = 0; i < 2; i++) {
[deacc58d]943 rc = label->bd.ops->read(label->bd.arg,
[bf7ddde]944 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
945 if (rc != EOK) {
946 rc = EIO;
[6a66923]947 goto exit;
[bf7ddde]948 }
949
950 gpt_hdr->pe_array_crc32 = host2uint32_t_le(crc);
951 gpt_hdr_compute_crc(gpt_hdr, label->lt.gpt.hdr_size);
952
[deacc58d]953 rc = label->bd.ops->write(label->bd.arg,
[bf7ddde]954 label->lt.gpt.hdr_ba[i], 1, gpt_hdr);
955 if (rc != EOK) {
956 rc = EIO;
[6a66923]957 goto exit;
[bf7ddde]958 }
959 }
[deacc58d]960
[6a66923]961 rc = EOK;
[deacc58d]962
[6a66923]963exit:
[bf7ddde]964 free(gpt_hdr);
965 return rc;
966}
967
968static void gpt_hdr_compute_crc(gpt_header_t *hdr, size_t hdr_size)
969{
970 uint32_t crc;
971
972 hdr->header_crc32 = 0;
973 crc = compute_crc32((uint8_t *)hdr, hdr_size);
974 hdr->header_crc32 = crc;
975}
976
[b7fd2a0]977static errno_t gpt_hdr_get_crc(gpt_header_t *hdr, size_t hdr_size, uint32_t *crc)
[bf7ddde]978{
979 gpt_header_t *c;
980
[eed70f1]981 c = calloc(1, hdr_size);
[bf7ddde]982 if (c == NULL)
983 return ENOMEM;
984
985 memcpy(c, hdr, hdr_size);
986 c->header_crc32 = 0;
987 *crc = compute_crc32((uint8_t *)c, hdr_size);
988 free(c);
989
990 return EOK;
991}
992
[cffa82aa]993/** Create GPT Protective MBR */
[b7fd2a0]994static errno_t gpt_pmbr_create(label_bd_t *bd, size_t bsize, uint64_t nblocks)
[cffa82aa]995{
996 mbr_br_block_t *pmbr = NULL;
997 uint64_t pmbr_nb;
[b7fd2a0]998 errno_t rc;
[cffa82aa]999
1000 pmbr = calloc(1, bsize);
1001 if (pmbr == NULL) {
1002 rc = ENOMEM;
1003 goto error;
1004 }
1005
1006 pmbr_nb = nblocks - gpt_hdr_ba;
1007
1008 pmbr->pte[0].ptype = mbr_pt_gpt_protect;
1009 pmbr->pte[0].first_lba = gpt_hdr_ba;
1010
1011 if (pmbr_nb <= UINT32_MAX)
1012 pmbr->pte[0].length = host2uint32_t_le((uint32_t)pmbr_nb);
1013 else
1014 pmbr->pte[0].length = host2uint32_t_le(UINT32_MAX);
1015
1016 pmbr->signature = host2uint16_t_le(mbr_br_signature);
1017
[deacc58d]1018 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
[cffa82aa]1019 if (rc != EOK) {
1020 rc = EIO;
1021 goto error;
1022 }
1023
1024 free(pmbr);
1025 return EOK;
1026error:
1027 free(pmbr);
1028 return rc;
1029}
1030
1031/** Destroy GPT Protective MBR */
[b7fd2a0]1032static errno_t gpt_pmbr_destroy(label_bd_t *bd, size_t bsize)
[cffa82aa]1033{
1034 mbr_br_block_t *pmbr = NULL;
[b7fd2a0]1035 errno_t rc;
[cffa82aa]1036
1037 pmbr = calloc(1, bsize);
1038 if (pmbr == NULL) {
1039 rc = ENOMEM;
1040 goto error;
1041 }
1042
[deacc58d]1043 rc = bd->ops->write(bd->arg, mbr_ba, 1, pmbr);
[cffa82aa]1044 if (rc != EOK) {
1045 rc = EIO;
1046 goto error;
1047 }
1048
1049 free(pmbr);
1050 return EOK;
1051error:
1052 free(pmbr);
1053 return rc;
1054}
1055
[3faa03d]1056/** @}
1057 */
Note: See TracBrowser for help on using the repository browser.