001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <sos/kmalloc.h>
020 #include <sos/blkdev.h>
021 #include <drivers/bochs.h>
022
023
024
025
026
027 typedef struct partition_entry
028 {
029 sos_ui8_t active;
030 sos_ui8_t start_dl;
031 sos_ui16_t start_cylinder;
032 sos_ui8_t type;
033 sos_ui8_t end_dl;
034 sos_ui16_t end_cylinder;
035 sos_ui32_t lba;
036 sos_ui32_t size;
037 } partition_entry_t;
038
039
040
041
042 #define PART_TABLE_OFFSET 446
043
044
045
046
047
048
049 #define PART_TYPE_EXTENDED 0x5
050 #define PART_TYPE_FAT16_1 0xe
051 #define PART_TYPE_FAT16_2 0x6
052 #define PART_TYPE_FAT32_1 0xb
053 #define PART_TYPE_FAT32_2 0xc
054 #define PART_TYPE_LINUX_SWAP 0x82
055 #define PART_TYPE_LINUX 0x83
056
057
058
059
060 static const char *
061 sos_part_type_str (unsigned int type)
062 {
063 switch (type)
064 {
065 case PART_TYPE_EXTENDED:
066 return "Extended";
067 case PART_TYPE_FAT16_1:
068 case PART_TYPE_FAT16_2:
069 return "FAT16";
070 case PART_TYPE_FAT32_1:
071 case PART_TYPE_FAT32_2:
072 return "FAT32";
073 case PART_TYPE_LINUX_SWAP:
074 return "Linux Swap";
075 case PART_TYPE_LINUX:
076 return "Linux";
077 default:
078 return "Unknown";
079 }
080 }
081
082
083
084
085
086 sos_ret_t
087 sos_part_detect (sos_ui32_t disk_class, sos_ui32_t disk_instance,
088 sos_size_t block_size, const char *name)
089 {
090 sos_vaddr_t buffer;
091 struct sos_blockdev_instance *blkdev;
092 struct partition_entry *part_entry;
093 unsigned int extstart = 0, extsup = 0;
094 sos_ret_t ret;
095 sos_size_t size = block_size;
096 unsigned int partnum;
097
098 blkdev = sos_blockdev_ref_instance (disk_class, disk_instance);
099 if (blkdev == NULL)
100 return -SOS_ENOENT;
101
102 buffer = (sos_vaddr_t) sos_kmalloc (block_size, 0);
103 if (buffer == 0)
104 {
105 sos_blockdev_release_instance (blkdev);
106 return -SOS_ENOMEM;
107 }
108
109 ret = sos_blockdev_kernel_read (blkdev, 0, buffer, & size);
110 if (ret != SOS_OK)
111 {
112 sos_blockdev_release_instance (blkdev);
113 sos_kfree (buffer);
114 return ret;
115 }
116
117 if (size != block_size)
118 {
119 sos_blockdev_release_instance (blkdev);
120 sos_kfree (buffer);
121 return -SOS_EIO;
122 }
123
124 part_entry = (struct partition_entry *) (buffer + PART_TABLE_OFFSET);
125
126
127 for (partnum = 0; partnum < 4; partnum++)
128 {
129 if (part_entry [partnum].size == 0)
130 continue;
131
132 sos_bochs_printf ("%s%d (%lu Mb, %s) ", name, partnum+1,
133 (part_entry[partnum].size * block_size >> 20),
134 sos_part_type_str(part_entry[partnum].type));
135 if (part_entry [partnum].type == PART_TYPE_EXTENDED)
136 {
137 if (extstart != 0)
138 sos_bochs_printf ("Warning: two extended partitions detected\n");
139 extstart = part_entry [partnum].lba;
140 continue;
141 }
142
143 ret = sos_blockdev_register_partition (disk_class,
144 disk_instance + partnum + 1,
145 blkdev,
146 part_entry[partnum].lba,
147 part_entry[partnum].size, NULL);
148 if (ret != SOS_OK)
149 {
150 sos_bochs_printf ("Could not register partition %d for disk %lu:%lu: error %d\n",
151 partnum, disk_class, disk_instance, ret);
152 continue;
153 }
154 }
155
156 while (extstart != 0 && partnum < 15)
157 {
158 ret = sos_blockdev_kernel_read (blkdev, (extstart + extsup) * block_size,
159 (sos_luoffset_t) buffer, & size);
160 if (ret != SOS_OK)
161 {
162 sos_blockdev_release_instance (blkdev);
163 sos_kfree (buffer);
164 return ret;
165 }
166
167 if (size != block_size)
168 {
169 sos_blockdev_release_instance (blkdev);
170 sos_kfree (buffer);
171 return -SOS_EIO;
172 }
173
174 sos_bochs_printf ("%s%d (%lu Mb, %s) ", name, partnum+1,
175 (part_entry[0].size * block_size >> 20),
176 sos_part_type_str(part_entry[0].type));
177
178 ret = sos_blockdev_register_partition (disk_class,
179 disk_instance + partnum + 1,
180 blkdev,
181 extstart + part_entry[0].lba,
182 part_entry[0].size, NULL);
183 if (ret != SOS_OK)
184 sos_bochs_printf ("Could not register partition %d for disk %lu:%lu: error %d\n",
185 partnum, disk_class, disk_instance, ret);
186
187 extsup = part_entry[1].lba;
188 partnum ++;
189 if (extsup == 0)
190 break;
191 }
192
193 sos_blockdev_release_instance (blkdev);
194 sos_kfree (buffer);
195 return SOS_OK;
196 }
197
198
199
200
201 sos_ret_t
202 sos_part_undetect (sos_ui32_t disk_class, sos_ui32_t disk_instance)
203 {
204 int partnum;
205 sos_ret_t ret;
206
207 for (partnum = 0; partnum < 15; partnum++)
208 {
209 ret = sos_blockdev_unregister_device (disk_class, disk_instance + partnum + 1);
210 if (ret != SOS_OK)
211 sos_bochs_printf ("Warning: could not unregister partition %d of device %lu:%lu\n",
212 partnum, disk_class, disk_instance);
213 }
214
215 return SOS_OK;
216 }