blob: 5565fe5531ae5e136758e8ea0d22249acacf0508 [file] [log] [blame]
Travis Geiselbrecht2dc9c972010-05-06 14:04:33 -07001/*
2 * Copyright (c) 2009 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <debug.h>
24#include <printf.h>
25#include <string.h>
26#include <compiler.h>
27#include <stdlib.h>
28#include <arch.h>
29#include <lib/bio.h>
30#include <lib/partition.h>
31
32struct chs {
33 uint8_t c;
34 uint8_t h;
35 uint8_t s;
36} __PACKED;
37
38struct mbr_part {
39 uint8_t status;
40 struct chs start;
41 uint8_t type;
42 struct chs end;
43 uint32_t lba_start;
44 uint32_t lba_length;
45} __PACKED;
46
47static status_t validate_mbr_partition(bdev_t *dev, const struct mbr_part *part)
48{
49 /* check for invalid types */
50 if (part->type == 0)
51 return -1;
52 /* check for invalid status */
53 if (part->status != 0x80 && part->status != 0x00)
54 return -1;
55
56 /* make sure the range fits within the device */
57 if (part->lba_start >= dev->block_count)
58 return -1;
59 if ((part->lba_start + part->lba_length) > dev->block_count)
60 return -1;
61
62 /* that's about all we can do, MBR has no other good way to see if it's valid */
63
64 return 0;
65}
66
67int partition_publish(const char *device, off_t offset)
68{
69 int err = 0;
70 int count = 0;
71
72 // clear any partitions that may have already existed
73 partition_unpublish(device);
74
75 bdev_t *dev = bio_open(device);
76 if (!dev) {
77 printf("partition_publish: unable to open device\n");
78 return -1;
79 }
80
81 // get a dma aligned and padded block to read info
82 STACKBUF_DMA_ALIGN(buf, dev->block_size);
83
84 /* sniff for MBR partition types */
85 do {
86 int i;
87
88 err = bio_read(dev, buf, offset, 512);
89 if (err < 0)
90 goto err;
91
92 /* look for the aa55 tag */
93 if (buf[510] != 0x55 || buf[511] != 0xaa)
94 break;
95
96 /* see if a partition table makes sense here */
97 struct mbr_part part[4];
98 memcpy(part, buf + 446, sizeof(part));
99
100#if DEBUGLEVEL >= INFO
101 dprintf(INFO, "mbr partition table dump:\n");
102 for (i=0; i < 4; i++) {
103 dprintf(INFO, "\t%i: status 0x%hhx, type 0x%hhx, start 0x%x, len 0x%x\n", i, part[i].status, part[i].type, part[i].lba_start, part[i].lba_length);
104 }
105#endif
106
107 /* validate each of the partition entries */
108 for (i=0; i < 4; i++) {
109 if (validate_mbr_partition(dev, &part[i]) >= 0) {
110 // publish it
111 char subdevice[128];
112
113 sprintf(subdevice, "%sp%d", device, i);
114
115 err = bio_publish_subdevice(device, subdevice, part[i].lba_start, part[i].lba_length);
116 if (err < 0) {
117 dprintf(INFO, "error publishing subdevice '%s'\n", subdevice);
118 continue;
119 }
120 count++;
121 }
122 }
123 } while(0);
124
125 bio_close(dev);
126
127err:
128 return (err < 0) ? err : count;
129}
130
131int partition_unpublish(const char *device)
132{
133 int i;
134 int count;
135 bdev_t *dev;
136 char devname[512];
137
138 count = 0;
139 for (i=0; i < 16; i++) {
140 sprintf(devname, "%sp%d", device, i);
141
142 dev = bio_open(devname);
143 if (!dev)
144 continue;
145
146 bio_unregister_device(dev);
147 bio_close(dev);
148 count++;
149 }
150
151 return count;
152}
153