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

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

Persistent partition table creation and destruction.

  • Property mode set to 100644
File size: 13.5 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
36#include <block.h>
37#include <byteorder.h>
38#include <errno.h>
[1626cd4]39#include <mem.h>
[3faa03d]40#include <stdlib.h>
41
42#include "std/gpt.h"
43#include "gpt.h"
44
45static int gpt_open(service_id_t, label_t **);
46static int gpt_create(service_id_t, label_t **);
47static void gpt_close(label_t *);
48static int gpt_destroy(label_t *);
[1626cd4]49static int gpt_get_info(label_t *, label_info_t *);
[3faa03d]50static label_part_t *gpt_part_first(label_t *);
51static label_part_t *gpt_part_next(label_part_t *);
52static void gpt_part_get_info(label_part_t *, label_part_info_t *);
53static int gpt_part_create(label_t *, label_part_spec_t *, label_part_t **);
54static int gpt_part_destroy(label_part_t *);
55
[99c23405]56static void gpt_unused_pte(gpt_entry_t *);
57static int gpt_part_to_pte(label_part_t *, gpt_entry_t *);
[1626cd4]58static int gpt_pte_to_part(label_t *, gpt_entry_t *, int);
[99c23405]59static int gpt_pte_update(label_t *, gpt_entry_t *, int);
[3faa03d]60
61const uint8_t efi_signature[8] = {
62 /* "EFI PART" in ASCII */
63 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
64};
65
66label_ops_t gpt_label_ops = {
67 .open = gpt_open,
68 .create = gpt_create,
69 .close = gpt_close,
70 .destroy = gpt_destroy,
[1626cd4]71 .get_info = gpt_get_info,
[3faa03d]72 .part_first = gpt_part_first,
73 .part_next = gpt_part_next,
74 .part_get_info = gpt_part_get_info,
75 .part_create = gpt_part_create,
76 .part_destroy = gpt_part_destroy
77};
78
79static int gpt_open(service_id_t sid, label_t **rlabel)
80{
81 label_t *label = NULL;
[99c23405]82 gpt_header_t *gpt_hdr[2];
[3faa03d]83 gpt_entry_t *eptr;
84 uint8_t *etable = NULL;
85 size_t bsize;
86 uint32_t num_entries;
87 uint32_t esize;
88 uint32_t bcnt;
[99c23405]89 uint64_t ptba[2];
90 uint64_t h1ba;
[3faa03d]91 uint32_t entry;
[1626cd4]92 uint64_t ba_min, ba_max;
[99c23405]93 int i, j;
[3faa03d]94 int rc;
95
[99c23405]96 gpt_hdr[0] = NULL;
97 gpt_hdr[1] = NULL;
98
[3faa03d]99 rc = block_get_bsize(sid, &bsize);
100 if (rc != EOK) {
101 rc = EIO;
102 goto error;
103 }
104
105 if (bsize < 512 || (bsize % 512) != 0) {
106 rc = EINVAL;
107 goto error;
108 }
109
[99c23405]110 gpt_hdr[0] = calloc(1, bsize);
111 if (gpt_hdr[0] == NULL) {
112 rc = ENOMEM;
113 goto error;
114 }
115
116 gpt_hdr[1] = calloc(1, bsize);
117 if (gpt_hdr[1] == NULL) {
[3faa03d]118 rc = ENOMEM;
119 goto error;
120 }
121
[603c1d1f]122 rc = block_read_direct(sid, gpt_hdr_ba, 1, gpt_hdr[0]);
[99c23405]123 if (rc != EOK) {
124 rc = EIO;
125 goto error;
126 }
127
128 h1ba = uint64_t_le2host(gpt_hdr[0]->alternate_lba);
129
130 rc = block_read_direct(sid, h1ba, 1, gpt_hdr[1]);
[3faa03d]131 if (rc != EOK) {
132 rc = EIO;
133 goto error;
134 }
135
136 label = calloc(1, sizeof(label_t));
137 if (label == NULL)
138 return ENOMEM;
139
140 list_initialize(&label->parts);
141
[99c23405]142 for (j = 0; j < 2; j++) {
143 for (i = 0; i < 8; ++i) {
144 if (gpt_hdr[j]->efi_signature[i] != efi_signature[i]) {
145 rc = EINVAL;
146 goto error;
147 }
[3faa03d]148 }
149 }
150
[99c23405]151 num_entries = uint32_t_le2host(gpt_hdr[0]->num_entries);
152 esize = uint32_t_le2host(gpt_hdr[0]->entry_size);
[3faa03d]153 bcnt = (num_entries + esize - 1) / esize;
[99c23405]154 ptba[0] = uint64_t_le2host(gpt_hdr[0]->entry_lba);
155 ptba[1] = uint64_t_le2host(gpt_hdr[1]->entry_lba);
156 ba_min = uint64_t_le2host(gpt_hdr[0]->first_usable_lba);
157 ba_max = uint64_t_le2host(gpt_hdr[0]->last_usable_lba);
[3faa03d]158
159 if (num_entries < 1) {
160 rc = EINVAL;
161 goto error;
162 }
163
164 if (esize < sizeof(gpt_entry_t)) {
165 rc = EINVAL;
166 goto error;
167 }
168
[1626cd4]169 if (ba_max < ba_min) {
170 rc = EINVAL;
171 goto error;
172 }
173
[3faa03d]174 etable = calloc(num_entries, esize);
175 if (etable == NULL) {
176 rc = ENOMEM;
177 goto error;
178 }
179
[99c23405]180 rc = block_read_direct(sid, ptba[0], bcnt, etable);
[3faa03d]181 if (rc != EOK) {
182 rc = EIO;
183 goto error;
184 }
185
186 for (entry = 0; entry < num_entries; entry++) {
187 eptr = (gpt_entry_t *)(etable + entry * esize);
[1626cd4]188 rc = gpt_pte_to_part(label, eptr, entry + 1);
[3faa03d]189 if (rc != EOK)
190 goto error;
191 }
192
193 free(etable);
194 etable = NULL;
[99c23405]195 free(gpt_hdr[0]);
196 gpt_hdr[0] = NULL;
197 free(gpt_hdr[1]);
198 gpt_hdr[1] = NULL;
[3faa03d]199
200 label->ops = &gpt_label_ops;
201 label->ltype = lt_gpt;
[603c1d1f]202 label->svc_id = sid;
[1626cd4]203 label->ablock0 = ba_min;
204 label->anblocks = ba_max - ba_min + 1;
[99c23405]205 label->pri_entries = num_entries;
206 label->block_size = bsize;
207
[603c1d1f]208 label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
209 label->lt.gpt.hdr_ba[1] = h1ba;
[99c23405]210 label->lt.gpt.ptable_ba[0] = ptba[0];
211 label->lt.gpt.ptable_ba[1] = ptba[1];
212 label->lt.gpt.esize = esize;
213
[3faa03d]214 *rlabel = label;
215 return EOK;
216error:
217 free(etable);
[99c23405]218 free(gpt_hdr[0]);
219 free(gpt_hdr[1]);
[3faa03d]220 free(label);
221 return rc;
222}
223
224static int gpt_create(service_id_t sid, label_t **rlabel)
225{
[603c1d1f]226 label_t *label = NULL;
227 gpt_header_t *gpt_hdr = NULL;
228 uint8_t *etable = NULL;
229 size_t bsize;
230 uint32_t num_entries;
231 uint32_t esize;
232 uint64_t ptba[2];
233 uint64_t hdr_ba[2];
234 uint64_t pt_blocks;
235 uint64_t ba_min, ba_max;
236 aoff64_t nblocks;
237 uint64_t resv_blocks;
238 int i, j;
239 int rc;
240
241 rc = block_get_bsize(sid, &bsize);
242 if (rc != EOK) {
243 rc = EIO;
244 goto error;
245 }
246
247 if (bsize < 512 || (bsize % 512) != 0) {
248 rc = EINVAL;
249 goto error;
250 }
251
252 rc = block_get_nblocks(sid, &nblocks);
253 if (rc != EOK) {
254 rc = EIO;
255 goto error;
256 }
257
258 /* Number of blocks of a partition table */
259 pt_blocks = gpt_ptable_min_size / bsize;
260 /* Minimum number of reserved (not allocatable) blocks */
261 resv_blocks = 3 + 2 * pt_blocks;
262
263 if (nblocks <= resv_blocks) {
264 rc = ENOSPC;
265 goto error;
266 }
267
268 hdr_ba[0] = gpt_hdr_ba;
269 hdr_ba[1] = nblocks - 1;
270 ptba[0] = 2;
271 ptba[1] = nblocks - 1 - pt_blocks;
272 ba_min = ptba[0] + pt_blocks;
273 ba_max = ptba[1] - 1;
274 esize = sizeof(gpt_entry_t);
275
276 num_entries = pt_blocks * bsize / sizeof(gpt_entry_t);
277
278 for (i = 0; i < 2; i++) {
279 gpt_hdr = calloc(1, bsize);
280 if (gpt_hdr == NULL) {
281 rc = ENOMEM;
282 goto error;
283 }
284
285 for (j = 0; j < 8; ++j)
286 gpt_hdr->efi_signature[j] = efi_signature[j];
287 gpt_hdr->revision = host2uint32_t_le(gpt_revision);
288 gpt_hdr->header_size = host2uint32_t_le(sizeof(gpt_header_t));
289 gpt_hdr->header_crc32 = 0; /* XXX */
290 gpt_hdr->my_lba = host2uint64_t_le(hdr_ba[i]);
291 gpt_hdr->alternate_lba = host2uint64_t_le(hdr_ba[1 - i]);
292 gpt_hdr->first_usable_lba = host2uint64_t_le(ba_min);
293 gpt_hdr->last_usable_lba = host2uint64_t_le(ba_max);
294 //gpt_hdr->disk_guid
295 gpt_hdr->entry_lba = host2uint64_t_le(ptba[i]);
296 gpt_hdr->num_entries = host2uint32_t_le(num_entries);
297 gpt_hdr->entry_size = host2uint32_t_le(esize);
298 gpt_hdr->pe_array_crc32 = 0; /* XXXX */
299
300 rc = block_write_direct(sid, hdr_ba[i], 1, gpt_hdr);
301 if (rc != EOK) {
302 rc = EIO;
303 goto error;
304 }
305
306 free(gpt_hdr);
307 gpt_hdr = NULL;
308
309 etable = calloc(num_entries, esize);
310 if (etable == NULL) {
311 rc = ENOMEM;
312 goto error;
313 }
314
315 rc = block_write_direct(sid, ptba[i], pt_blocks, etable);
316 if (rc != EOK) {
317 rc = EIO;
318 goto error;
319 }
320
321 free(etable);
322 etable = 0;
323 }
324
325 label = calloc(1, sizeof(label_t));
326 if (label == NULL)
327 return ENOMEM;
328
329 list_initialize(&label->parts);
330
331 label->ops = &gpt_label_ops;
332 label->ltype = lt_gpt;
333 label->svc_id = sid;
334 label->ablock0 = ba_min;
335 label->anblocks = ba_max - ba_min + 1;
336 label->pri_entries = num_entries;
337 label->block_size = bsize;
338
339 label->lt.gpt.hdr_ba[0] = hdr_ba[0];
340 label->lt.gpt.hdr_ba[1] = hdr_ba[1];
341 label->lt.gpt.ptable_ba[0] = ptba[0];
342 label->lt.gpt.ptable_ba[1] = ptba[1];
343 label->lt.gpt.esize = esize;
344
345 *rlabel = label;
[3faa03d]346 return EOK;
[603c1d1f]347error:
348 free(etable);
349 free(gpt_hdr);
350 free(label);
351 return rc;
[3faa03d]352}
353
354static void gpt_close(label_t *label)
355{
[603c1d1f]356 label_part_t *part;
357
358 part = gpt_part_first(label);
359 while (part != NULL) {
360 list_remove(&part->llabel);
361 free(part);
362 part = gpt_part_first(label);
363 }
364
[3faa03d]365 free(label);
366}
367
368static int gpt_destroy(label_t *label)
369{
[603c1d1f]370 gpt_header_t *gpt_hdr = NULL;
371 uint8_t *etable = NULL;
372 label_part_t *part;
373 uint64_t pt_blocks;
374 int i;
375 int rc;
376
377 part = gpt_part_first(label);
378 if (part != NULL) {
379 rc = ENOTEMPTY;
380 goto error;
381 }
382
383 pt_blocks = label->pri_entries * label->lt.gpt.esize /
384 label->block_size;
385
386 for (i = 0; i < 2; i++) {
387 gpt_hdr = calloc(1, label->block_size);
388 if (gpt_hdr == NULL) {
389 rc = ENOMEM;
390 goto error;
391 }
392
393 rc = block_write_direct(label->svc_id, label->lt.gpt.hdr_ba[i],
394 1, gpt_hdr);
395 if (rc != EOK) {
396 rc = EIO;
397 goto error;
398 }
399
400 free(gpt_hdr);
401 gpt_hdr = NULL;
402
403 etable = calloc(label->pri_entries, label->lt.gpt.esize);
404 if (etable == NULL) {
405 rc = ENOMEM;
406 goto error;
407 }
408
409 rc = block_write_direct(label->svc_id,
410 label->lt.gpt.ptable_ba[i], pt_blocks, etable);
411 if (rc != EOK) {
412 rc = EIO;
413 goto error;
414 }
415
416 free(etable);
417 etable = 0;
418 }
419
420 free(label);
[3faa03d]421 return EOK;
[603c1d1f]422error:
423 return rc;
[3faa03d]424}
425
[1626cd4]426static int gpt_get_info(label_t *label, label_info_t *linfo)
427{
428 memset(linfo, 0, sizeof(label_info_t));
429 linfo->dcnt = dc_label;
430 linfo->ltype = lt_gpt;
431 linfo->ablock0 = label->ablock0;
432 linfo->anblocks = label->anblocks;
433 return EOK;
434}
435
[3faa03d]436static label_part_t *gpt_part_first(label_t *label)
437{
438 link_t *link;
439
440 link = list_first(&label->parts);
441 if (link == NULL)
442 return NULL;
443
444 return list_get_instance(link, label_part_t, llabel);
445}
446
447static label_part_t *gpt_part_next(label_part_t *part)
448{
449 link_t *link;
450
451 link = list_next(&part->llabel, &part->label->parts);
452 if (link == NULL)
453 return NULL;
454
455 return list_get_instance(link, label_part_t, llabel);
456}
457
458static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
459{
[1626cd4]460 pinfo->index = part->index;
[3faa03d]461 pinfo->block0 = part->block0;
462 pinfo->nblocks = part->nblocks;
463}
464
465static int gpt_part_create(label_t *label, label_part_spec_t *pspec,
466 label_part_t **rpart)
467{
[6bc542b]468 label_part_t *part;
[99c23405]469 gpt_entry_t pte;
470 int rc;
[6bc542b]471
472 part = calloc(1, sizeof(label_part_t));
[99c23405]473 if (part == NULL) {
474 rc = ENOMEM;
475 goto error;
476 }
[6bc542b]477
478 /* XXX Verify index, block0, nblocks */
479
[99c23405]480 if (pspec->index < 1 || pspec->index > label->pri_entries) {
481 rc = EINVAL;
482 goto error;
483 }
484
485 /* XXX Check if index is used */
486
487 part->label = label;
[6bc542b]488 part->index = pspec->index;
489 part->block0 = pspec->block0;
490 part->nblocks = pspec->nblocks;
[99c23405]491 part->ptype = pspec->ptype;
492
493 /* Prepare partition table entry */
494 rc = gpt_part_to_pte(part, &pte);
495 if (rc != EOK) {
496 rc = EINVAL;
497 goto error;
498 }
[6bc542b]499
[99c23405]500 /* Modify partition tables */
501 rc = gpt_pte_update(label, &pte, pspec->index - 1);
502 if (rc != EOK) {
503 rc = EIO;
504 goto error;
505 }
[6bc542b]506
507 list_append(&part->llabel, &label->parts);
508
509 *rpart = part;
510 return EOK;
[99c23405]511error:
512 free(part);
513 return rc;
[3faa03d]514}
515
516static int gpt_part_destroy(label_part_t *part)
517{
[99c23405]518 gpt_entry_t pte;
519 int rc;
520
521 /* Prepare unused partition table entry */
522 gpt_unused_pte(&pte);
523
524 /* Modify partition tables */
525 rc = gpt_pte_update(part->label, &pte, part->index - 1);
526 if (rc != EOK)
527 return EIO;
528
529 list_remove(&part->llabel);
530 free(part);
531 return EOK;
532}
533
534static void gpt_unused_pte(gpt_entry_t *pte)
535{
536 memset(pte, 0, sizeof(gpt_entry_t));
537}
538
539static int gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
540{
541 uint64_t eblock;
542
543 eblock = part->block0 + part->nblocks - 1;
544 if (eblock < part->block0)
545 return EINVAL;
546
547 memset(pte, 0, sizeof(gpt_entry_t));
548 pte->part_type[0] = 0x12;
549 pte->part_id[0] = 0x34;
550 pte->start_lba = host2uint64_t_le(part->block0);
551 pte->end_lba = host2uint64_t_le(eblock);
552// pte->attributes
553// pte->part_name
554 return EOK;
[3faa03d]555}
556
[1626cd4]557static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
[3faa03d]558{
559 label_part_t *part;
560 bool present;
561 uint64_t b0, b1;
562 int i;
563
564 present = false;
565 for (i = 0; i < 8; i++)
566 if (pte->part_type[i] != 0x00)
567 present = true;
568
569 if (!present)
570 return EOK;
571
572 part = calloc(1, sizeof(label_part_t));
573 if (part == NULL)
574 return ENOMEM;
575
576 b0 = uint64_t_le2host(pte->start_lba);
577 b1 = uint64_t_le2host(pte->end_lba);
578 if (b1 <= b0)
579 return EINVAL;
580
[1626cd4]581 part->index = index;
[3faa03d]582 part->block0 = b0;
583 part->nblocks = b1 - b0 + 1;
584
585 part->label = label;
586 list_append(&part->llabel, &label->parts);
587 return EOK;
588}
589
[99c23405]590/** Update partition table entry at specified index.
591 *
592 * Replace partition entry at index @a index with the contents of
593 * @a pte.
594 */
595static int gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
596{
597 size_t pos;
598 size_t offs;
599 uint64_t ba;
600 uint8_t *buf;
601 gpt_entry_t *e;
602 int i;
603 int rc;
604
605 pos = index * label->lt.gpt.esize;
606 offs = pos % label->block_size;
607
608 buf = calloc(1, label->block_size);
609 if (buf == NULL)
610 return ENOMEM;
611
612 /* For both partition tables: read, modify, write */
613 for (i = 0; i < 2; i++) {
614 ba = label->lt.gpt.ptable_ba[i] +
615 pos / label->block_size;
616
[603c1d1f]617 rc = block_read_direct(label->svc_id, ba, 1, buf);
[99c23405]618 if (rc != EOK) {
619 rc = EIO;
620 goto error;
621 }
622
623 /* Replace single entry */
624 e = (gpt_entry_t *)(&buf[offs]);
625 *e = *pte;
626
[603c1d1f]627 rc = block_write_direct(label->svc_id, ba, 1, buf);
[99c23405]628 if (rc != EOK) {
629 rc = EIO;
630 goto error;
631 }
632 }
633
634 free(buf);
635 return EOK;
636error:
637 free(buf);
638 return rc;
639}
640
[3faa03d]641/** @}
642 */
Note: See TracBrowser for help on using the repository browser.