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

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

Most of logical partition support.

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