source: mainline/uspace/lib/label/src/mbr.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: 9.5 KB
Line 
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 Master Boot Record label
34 */
35
36#include <block.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <mem.h>
40#include <stdlib.h>
41
42#include "std/mbr.h"
43#include "mbr.h"
44
45static int mbr_open(service_id_t, label_t **);
46static int mbr_create(service_id_t, label_t **);
47static void mbr_close(label_t *);
48static int mbr_destroy(label_t *);
49static int mbr_get_info(label_t *, label_info_t *);
50static label_part_t *mbr_part_first(label_t *);
51static label_part_t *mbr_part_next(label_part_t *);
52static void mbr_part_get_info(label_part_t *, label_part_info_t *);
53static int mbr_part_create(label_t *, label_part_spec_t *, label_part_t **);
54static int mbr_part_destroy(label_part_t *);
55
56static void mbr_unused_pte(mbr_pte_t *);
57static int mbr_part_to_pte(label_part_t *, mbr_pte_t *);
58static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
59static int mbr_pte_update(label_t *, mbr_pte_t *, int);
60
61label_ops_t mbr_label_ops = {
62 .open = mbr_open,
63 .create = mbr_create,
64 .close = mbr_close,
65 .destroy = mbr_destroy,
66 .get_info = mbr_get_info,
67 .part_first = mbr_part_first,
68 .part_next = mbr_part_next,
69 .part_get_info = mbr_part_get_info,
70 .part_create = mbr_part_create,
71 .part_destroy = mbr_part_destroy
72};
73
74static int mbr_open(service_id_t sid, label_t **rlabel)
75{
76 label_t *label = NULL;
77 mbr_br_block_t *mbr = NULL;
78 mbr_pte_t *eptr;
79 uint16_t sgn;
80 size_t bsize;
81 aoff64_t nblocks;
82 uint32_t entry;
83 int rc;
84
85 rc = block_get_bsize(sid, &bsize);
86 if (rc != EOK) {
87 rc = EIO;
88 goto error;
89 }
90
91 rc = block_get_nblocks(sid, &nblocks);
92 if (rc != EOK) {
93 rc = EIO;
94 goto error;
95 }
96
97 if (bsize < 512 || (bsize % 512) != 0) {
98 rc = EINVAL;
99 goto error;
100 }
101
102 if (nblocks < mbr_ablock0) {
103 rc = EINVAL;
104 goto error;
105 }
106
107 mbr = calloc(1, bsize);
108 if (mbr == NULL) {
109 rc = ENOMEM;
110 goto error;
111 }
112
113 rc = block_read_direct(sid, mbr_ba, 1, mbr);
114 if (rc != EOK) {
115 rc = EIO;
116 goto error;
117 }
118
119 label = calloc(1, sizeof(label_t));
120 if (label == NULL)
121 return ENOMEM;
122
123 list_initialize(&label->parts);
124
125 /* Verify boot record signature */
126 sgn = uint16_t_le2host(mbr->signature);
127 if (sgn != mbr_br_signature) {
128 rc = EIO;
129 goto error;
130 }
131
132 for (entry = 0; entry < mbr_nprimary; entry++) {
133 eptr = &mbr->pte[entry];
134 rc = mbr_pte_to_part(label, eptr, entry + 1);
135 if (rc != EOK)
136 goto error;
137 }
138
139 free(mbr);
140 mbr = NULL;
141
142 label->ops = &mbr_label_ops;
143 label->ltype = lt_mbr;
144 label->svc_id = sid;
145 label->block_size = bsize;
146 label->ablock0 = mbr_ablock0;
147 label->anblocks = nblocks - mbr_ablock0;
148 label->pri_entries = mbr_nprimary;
149 *rlabel = label;
150 return EOK;
151error:
152 free(mbr);
153 free(label);
154 return rc;
155}
156
157static int mbr_create(service_id_t sid, label_t **rlabel)
158{
159 label_t *label = NULL;
160 mbr_br_block_t *mbr = NULL;
161 aoff64_t nblocks;
162 size_t bsize;
163 int i;
164 int rc;
165
166 rc = block_get_bsize(sid, &bsize);
167 if (rc != EOK) {
168 rc = EIO;
169 goto error;
170 }
171
172 rc = block_get_nblocks(sid, &nblocks);
173 if (rc != EOK) {
174 rc = EIO;
175 goto error;
176 }
177
178 mbr = calloc(1, bsize);
179 if (mbr == NULL) {
180 rc = ENOMEM;
181 goto error;
182 }
183
184 label = calloc(1, sizeof(label_t));
185 if (label == NULL)
186 return ENOMEM;
187
188 list_initialize(&label->parts);
189
190 mbr->media_id = 0;
191 mbr->pad0 = 0;
192 for (i = 0; i < mbr_nprimary; i++)
193 mbr_unused_pte(&mbr->pte[i]);
194 mbr->signature = host2uint16_t_le(mbr_br_signature);
195
196 rc = block_write_direct(sid, mbr_ba, 1, mbr);
197 if (rc != EOK) {
198 rc = EIO;
199 goto error;
200 }
201
202 free(mbr);
203 mbr = NULL;
204
205 label->ops = &mbr_label_ops;
206 label->ltype = lt_mbr;
207 label->block_size = bsize;
208 label->svc_id = sid;
209 label->ablock0 = mbr_ablock0;
210 label->anblocks = nblocks - mbr_ablock0;
211 label->pri_entries = mbr_nprimary;
212
213 *rlabel = label;
214 return EOK;
215error:
216 free(mbr);
217 free(label);
218 return rc;
219}
220
221static void mbr_close(label_t *label)
222{
223 label_part_t *part;
224
225 part = mbr_part_first(label);
226 while (part != NULL) {
227 list_remove(&part->llabel);
228 free(part);
229
230 part = mbr_part_first(label);
231 }
232
233 free(label);
234}
235
236static int mbr_destroy(label_t *label)
237{
238 mbr_br_block_t *mbr = NULL;
239 label_part_t *part;
240 int rc;
241
242 part = mbr_part_first(label);
243 if (part != NULL) {
244 rc = ENOTEMPTY;
245 goto error;
246 }
247
248 mbr = calloc(1, label->block_size);
249 if (mbr == NULL) {
250 rc = ENOMEM;
251 goto error;
252 }
253
254 rc = block_write_direct(label->svc_id, mbr_ba, 1, mbr);
255 if (rc != EOK) {
256 rc = EIO;
257 goto error;
258 }
259
260 free(mbr);
261 mbr = NULL;
262
263 free(label);
264 return EOK;
265error:
266 free(mbr);
267 return rc;
268}
269
270static int mbr_get_info(label_t *label, label_info_t *linfo)
271{
272 memset(linfo, 0, sizeof(label_info_t));
273 linfo->dcnt = dc_label;
274 linfo->ltype = lt_mbr;
275 linfo->ablock0 = label->ablock0;
276 linfo->anblocks = label->anblocks;
277 return EOK;
278}
279
280static label_part_t *mbr_part_first(label_t *label)
281{
282 link_t *link;
283
284 link = list_first(&label->parts);
285 if (link == NULL)
286 return NULL;
287
288 return list_get_instance(link, label_part_t, llabel);
289}
290
291static label_part_t *mbr_part_next(label_part_t *part)
292{
293 link_t *link;
294
295 link = list_next(&part->llabel, &part->label->parts);
296 if (link == NULL)
297 return NULL;
298
299 return list_get_instance(link, label_part_t, llabel);
300}
301
302static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
303{
304 pinfo->index = part->index;
305 pinfo->block0 = part->block0;
306 pinfo->nblocks = part->nblocks;
307}
308
309static int mbr_part_create(label_t *label, label_part_spec_t *pspec,
310 label_part_t **rpart)
311{
312 label_part_t *part;
313 mbr_pte_t pte;
314 int rc;
315
316 part = calloc(1, sizeof(label_part_t));
317 if (part == NULL)
318 return ENOMEM;
319
320 /* XXX Verify index, block0, nblocks */
321
322 if (pspec->index < 1 || pspec->index > label->pri_entries) {
323 rc = EINVAL;
324 goto error;
325 }
326
327 /* XXX Check if index is used */
328
329 part->label = label;
330 part->index = pspec->index;
331 part->block0 = pspec->block0;
332 part->nblocks = pspec->nblocks;
333 part->ptype = pspec->ptype;
334
335 rc = mbr_part_to_pte(part, &pte);
336 if (rc != EOK) {
337 rc = EINVAL;
338 goto error;
339 }
340
341 rc = mbr_pte_update(label, &pte, pspec->index - 1);
342 if (rc != EOK) {
343 rc = EIO;
344 goto error;
345 }
346
347 list_append(&part->llabel, &label->parts);
348
349 *rpart = part;
350 return EOK;
351error:
352 free(part);
353 return rc;
354}
355
356static int mbr_part_destroy(label_part_t *part)
357{
358 mbr_pte_t pte;
359 int rc;
360
361 /* Prepare unused partition table entry */
362 mbr_unused_pte(&pte);
363
364 /* Modify partition table */
365 rc = mbr_pte_update(part->label, &pte, part->index - 1);
366 if (rc != EOK)
367 return EIO;
368
369 list_remove(&part->llabel);
370 free(part);
371 return EOK;
372}
373
374static void mbr_unused_pte(mbr_pte_t *pte)
375{
376 memset(pte, 0, sizeof(mbr_pte_t));
377}
378
379static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
380{
381 if ((part->block0 >> 32) != 0)
382 return EINVAL;
383 if ((part->nblocks >> 32) != 0)
384 return EINVAL;
385 if ((part->ptype >> 8) != 0)
386 return EINVAL;
387
388 memset(pte, 0, sizeof(mbr_pte_t));
389 pte->ptype = part->ptype;
390 pte->first_lba = host2uint32_t_le(part->block0);
391 pte->length = host2uint32_t_le(part->nblocks);
392 return EOK;
393}
394
395static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
396{
397 label_part_t *part;
398 uint32_t block0;
399 uint32_t nblocks;
400
401 block0 = uint32_t_le2host(pte->first_lba);
402 nblocks = uint32_t_le2host(pte->length);
403
404 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
405 if (pte->ptype == mbr_pt_unused || pte->ptype == mbr_pt_extended ||
406 nblocks == 0)
407 return EOK;
408
409 part = calloc(1, sizeof(label_part_t));
410 if (part == NULL)
411 return ENOMEM;
412
413 part->index = index;
414 part->block0 = block0;
415 part->nblocks = nblocks;
416
417 /*
418 * TODO: Verify
419 * - partition must reside on disk
420 * - partition must not overlap any other partition
421 */
422
423 part->label = label;
424 list_append(&part->llabel, &label->parts);
425 return EOK;
426}
427
428/** Update partition table entry at specified index.
429 *
430 * Replace partition entry at index @a index with the contents of
431 * @a pte.
432 */
433static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
434{
435 mbr_br_block_t *br;
436 int rc;
437
438 br = calloc(1, label->block_size);
439 if (br == NULL)
440 return ENOMEM;
441
442 rc = block_read_direct(label->svc_id, mbr_ba, 1, br);
443 if (rc != EOK) {
444 rc = EIO;
445 goto error;
446 }
447
448 br->pte[index] = *pte;
449
450 rc = block_write_direct(label->svc_id, mbr_ba, 1, br);
451 if (rc != EOK) {
452 rc = EIO;
453 goto error;
454 }
455
456 free(br);
457 return EOK;
458error:
459 free(br);
460 return rc;
461}
462
463/** @}
464 */
Note: See TracBrowser for help on using the repository browser.