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

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

Persistent partition table modification when creating or deleting partition.

  • Property mode set to 100644
File size: 9.6 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
[99c23405]122 rc = block_read_direct(sid, GPT_HDR_BA, 1, gpt_hdr[0]);
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;
[99c23405]202 label->svcid = 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
208 label->lt.gpt.ptable_ba[0] = ptba[0];
209 label->lt.gpt.ptable_ba[1] = ptba[1];
210 label->lt.gpt.esize = esize;
211
[3faa03d]212 *rlabel = label;
213 return EOK;
214error:
215 free(etable);
[99c23405]216 free(gpt_hdr[0]);
217 free(gpt_hdr[1]);
[3faa03d]218 free(label);
219 return rc;
220}
221
222static int gpt_create(service_id_t sid, label_t **rlabel)
223{
224 return EOK;
225}
226
227static void gpt_close(label_t *label)
228{
229 free(label);
230}
231
232static int gpt_destroy(label_t *label)
233{
234 return EOK;
235}
236
[1626cd4]237static int gpt_get_info(label_t *label, label_info_t *linfo)
238{
239 memset(linfo, 0, sizeof(label_info_t));
240 linfo->dcnt = dc_label;
241 linfo->ltype = lt_gpt;
242 linfo->ablock0 = label->ablock0;
243 linfo->anblocks = label->anblocks;
244 return EOK;
245}
246
[3faa03d]247static label_part_t *gpt_part_first(label_t *label)
248{
249 link_t *link;
250
251 link = list_first(&label->parts);
252 if (link == NULL)
253 return NULL;
254
255 return list_get_instance(link, label_part_t, llabel);
256}
257
258static label_part_t *gpt_part_next(label_part_t *part)
259{
260 link_t *link;
261
262 link = list_next(&part->llabel, &part->label->parts);
263 if (link == NULL)
264 return NULL;
265
266 return list_get_instance(link, label_part_t, llabel);
267}
268
269static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
270{
[1626cd4]271 pinfo->index = part->index;
[3faa03d]272 pinfo->block0 = part->block0;
273 pinfo->nblocks = part->nblocks;
274}
275
276static int gpt_part_create(label_t *label, label_part_spec_t *pspec,
277 label_part_t **rpart)
278{
[6bc542b]279 label_part_t *part;
[99c23405]280 gpt_entry_t pte;
281 int rc;
[6bc542b]282
283 part = calloc(1, sizeof(label_part_t));
[99c23405]284 if (part == NULL) {
285 rc = ENOMEM;
286 goto error;
287 }
[6bc542b]288
289 /* XXX Verify index, block0, nblocks */
290
[99c23405]291 if (pspec->index < 1 || pspec->index > label->pri_entries) {
292 rc = EINVAL;
293 goto error;
294 }
295
296 /* XXX Check if index is used */
297
298 part->label = label;
[6bc542b]299 part->index = pspec->index;
300 part->block0 = pspec->block0;
301 part->nblocks = pspec->nblocks;
[99c23405]302 part->ptype = pspec->ptype;
303
304 /* Prepare partition table entry */
305 rc = gpt_part_to_pte(part, &pte);
306 if (rc != EOK) {
307 rc = EINVAL;
308 goto error;
309 }
[6bc542b]310
[99c23405]311 /* Modify partition tables */
312 rc = gpt_pte_update(label, &pte, pspec->index - 1);
313 if (rc != EOK) {
314 rc = EIO;
315 goto error;
316 }
[6bc542b]317
318 list_append(&part->llabel, &label->parts);
319
320 *rpart = part;
321 return EOK;
[99c23405]322error:
323 free(part);
324 return rc;
[3faa03d]325}
326
327static int gpt_part_destroy(label_part_t *part)
328{
[99c23405]329 gpt_entry_t pte;
330 int rc;
331
332 /* Prepare unused partition table entry */
333 gpt_unused_pte(&pte);
334
335 /* Modify partition tables */
336 rc = gpt_pte_update(part->label, &pte, part->index - 1);
337 if (rc != EOK)
338 return EIO;
339
340 list_remove(&part->llabel);
341 free(part);
342 return EOK;
343}
344
345static void gpt_unused_pte(gpt_entry_t *pte)
346{
347 memset(pte, 0, sizeof(gpt_entry_t));
348}
349
350static int gpt_part_to_pte(label_part_t *part, gpt_entry_t *pte)
351{
352 uint64_t eblock;
353
354 eblock = part->block0 + part->nblocks - 1;
355 if (eblock < part->block0)
356 return EINVAL;
357
358 memset(pte, 0, sizeof(gpt_entry_t));
359 pte->part_type[0] = 0x12;
360 pte->part_id[0] = 0x34;
361 pte->start_lba = host2uint64_t_le(part->block0);
362 pte->end_lba = host2uint64_t_le(eblock);
363// pte->attributes
364// pte->part_name
365 return EOK;
[3faa03d]366}
367
[1626cd4]368static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
[3faa03d]369{
370 label_part_t *part;
371 bool present;
372 uint64_t b0, b1;
373 int i;
374
375 present = false;
376 for (i = 0; i < 8; i++)
377 if (pte->part_type[i] != 0x00)
378 present = true;
379
380 if (!present)
381 return EOK;
382
383 part = calloc(1, sizeof(label_part_t));
384 if (part == NULL)
385 return ENOMEM;
386
387 b0 = uint64_t_le2host(pte->start_lba);
388 b1 = uint64_t_le2host(pte->end_lba);
389 if (b1 <= b0)
390 return EINVAL;
391
[1626cd4]392 part->index = index;
[3faa03d]393 part->block0 = b0;
394 part->nblocks = b1 - b0 + 1;
395
396 part->label = label;
397 list_append(&part->llabel, &label->parts);
398 return EOK;
399}
400
[99c23405]401/** Update partition table entry at specified index.
402 *
403 * Replace partition entry at index @a index with the contents of
404 * @a pte.
405 */
406static int gpt_pte_update(label_t *label, gpt_entry_t *pte, int index)
407{
408 size_t pos;
409 size_t offs;
410 uint64_t ba;
411 uint8_t *buf;
412 gpt_entry_t *e;
413 int i;
414 int rc;
415
416 pos = index * label->lt.gpt.esize;
417 offs = pos % label->block_size;
418
419 buf = calloc(1, label->block_size);
420 if (buf == NULL)
421 return ENOMEM;
422
423 /* For both partition tables: read, modify, write */
424 for (i = 0; i < 2; i++) {
425 ba = label->lt.gpt.ptable_ba[i] +
426 pos / label->block_size;
427
428 rc = block_read_direct(label->svcid, ba, 1, buf);
429 if (rc != EOK) {
430 rc = EIO;
431 goto error;
432 }
433
434 /* Replace single entry */
435 e = (gpt_entry_t *)(&buf[offs]);
436 *e = *pte;
437
438 rc = block_write_direct(label->svcid, ba, 1, buf);
439 if (rc != EOK) {
440 rc = EIO;
441 goto error;
442 }
443 }
444
445 free(buf);
446 return EOK;
447error:
448 free(buf);
449 return rc;
450}
451
[3faa03d]452/** @}
453 */
Note: See TracBrowser for help on using the repository browser.