1 /*
2 * Copyright (c) 2009 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lk/debug.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <lk/compiler.h>
12 #include <stdlib.h>
13 #include <arch.h>
14 #include <lib/bio.h>
15 #include <lib/partition.h>
16
17 struct chs {
18 uint8_t c;
19 uint8_t h;
20 uint8_t s;
21 } __PACKED;
22
23 struct mbr_part {
24 uint8_t status;
25 struct chs start;
26 uint8_t type;
27 struct chs end;
28 uint32_t lba_start;
29 uint32_t lba_length;
30 } __PACKED;
31
validate_mbr_partition(bdev_t * dev,const struct mbr_part * part)32 static status_t validate_mbr_partition(bdev_t *dev, const struct mbr_part *part) {
33 /* check for invalid types */
34 if (part->type == 0)
35 return -1;
36 /* check for invalid status */
37 if (part->status != 0x80 && part->status != 0x00)
38 return -1;
39
40 /* make sure the range fits within the device */
41 if (part->lba_start >= dev->block_count)
42 return -1;
43 if ((part->lba_start + part->lba_length) > dev->block_count)
44 return -1;
45
46 /* that's about all we can do, MBR has no other good way to see if it's valid */
47
48 return 0;
49 }
50
partition_publish(const char * device,off_t offset)51 int partition_publish(const char *device, off_t offset) {
52 int err = 0;
53 int count = 0;
54
55 // clear any partitions that may have already existed
56 partition_unpublish(device);
57
58 bdev_t *dev = bio_open(device);
59 if (!dev) {
60 printf("partition_publish: unable to open device\n");
61 return -1;
62 }
63
64 // get a dma aligned and padded block to read info
65 STACKBUF_DMA_ALIGN(buf, dev->block_size);
66
67 /* sniff for MBR partition types */
68 do {
69 int i;
70
71 err = bio_read(dev, buf, offset, 512);
72 if (err < 0)
73 goto err;
74
75 /* look for the aa55 tag */
76 if (buf[510] != 0x55 || buf[511] != 0xaa)
77 break;
78
79 /* see if a partition table makes sense here */
80 struct mbr_part part[4];
81 memcpy(part, buf + 446, sizeof(part));
82
83 #if LK_DEBUGLEVEL >= INFO
84 dprintf(INFO, "mbr partition table dump:\n");
85 for (i=0; i < 4; i++) {
86 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);
87 }
88 #endif
89
90 /* validate each of the partition entries */
91 for (i=0; i < 4; i++) {
92 if (validate_mbr_partition(dev, &part[i]) >= 0) {
93 // publish it
94 char subdevice[128];
95
96 sprintf(subdevice, "%sp%d", device, i);
97
98 err = bio_publish_subdevice(device, subdevice, part[i].lba_start, part[i].lba_length);
99 if (err < 0) {
100 dprintf(INFO, "error publishing subdevice '%s'\n", subdevice);
101 continue;
102 }
103 count++;
104 }
105 }
106 } while (0);
107
108 bio_close(dev);
109
110 err:
111 return (err < 0) ? err : count;
112 }
113
partition_unpublish(const char * device)114 int partition_unpublish(const char *device) {
115 int i;
116 int count;
117 bdev_t *dev;
118 char devname[512];
119
120 count = 0;
121 for (i=0; i < 16; i++) {
122 sprintf(devname, "%sp%d", device, i);
123
124 dev = bio_open(devname);
125 if (!dev)
126 continue;
127
128 bio_unregister_device(dev);
129 bio_close(dev);
130 count++;
131 }
132
133 return count;
134 }
135
136