/[pearpc]/src/io/prom/fs/part.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/io/prom/fs/part.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 6 months ago) by dpavlin
File size: 15204 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * part.cc
4 *
5 * Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
6 *
7 * Some ideas and code from yaboot/fs.c
8 * Copyright Ethan Beson and Benjamin Herrenschmidt
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 // for HFS+ info:
24 // http://developer.apple.com/technotes/tn/tn1150.html
25 //
26 // for HFS-MDB info:
27 // http://developer.apple.com/documentation/Carbon/Reference/File_Manager/file_manager/data_type_62.html
28
29 #include <cstring>
30
31 #include "debug/tracers.h"
32 #include "tools/endianess.h"
33 #include "tools/snprintf.h"
34 #include "tools/except.h"
35 #include "part.h"
36 #include "hfs.h"
37 #include "hfsplus.h"
38
39 #define APPLE_PARTITION_STATUS_BOOTABLE 8
40
41 #define APPLE_DRIVER_MAGIC MAGIC16("ER")
42 #define APPLE_PARTITION_MAGIC MAGIC16("PM")
43
44 struct ApplePartition {
45 uint16 signature;
46 uint16 res;
47 uint32 map_count;
48 uint32 start_block;
49 uint32 block_count;
50 char name[32];
51 char type[32];
52 uint32 data_start;
53 uint32 data_count;
54 uint32 status;
55 uint32 boot_start;
56 uint32 boot_size;
57 uint32 boot_load;
58 uint32 boot_load2;
59 uint32 boot_entry;
60 uint32 boot_entry2;
61 uint32 boot_cksum;
62 char processor[16];
63 };
64
65 byte ApplePartition_struct[]= {
66 STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST,
67 STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST,
68 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
69 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
70 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
71
72 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
73 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
74 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
75 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
76 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
77 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
78 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
79 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
80
81 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
82 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
83 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
84 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
85 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
86 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
87 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
88 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
89
90 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
91 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
92 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
93 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
94 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
95 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
96 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
97 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
98 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
99 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
100
101 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
102 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
103 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
104 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
105 0,
106 };
107
108 /*
109 *
110 */
111 #define ACTIVE_FLAG 0x80
112
113 #define EXTENDED 0x05
114 #define LINUX_PARTITION 0x81
115 #define LINUX_SWAP 0x82
116 #define LINUX_NATIVE 0x83
117 #define LINUX_EXTENDED 0x85
118
119 struct FDiskPartition {
120 uint8 boot_ind;
121 uint8 head;
122 uint8 sector;
123 uint8 cyl;
124 uint8 sys_ind;
125 uint8 end_head;
126 uint8 end_sector;
127 uint8 end_cyl;
128 uint32 start;
129 uint32 size;
130 };
131
132 byte FDiskPartition_struct[] = {
133 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
134 STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8, STRUCT_ENDIAN_8,
135 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
136 STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST,
137 0,
138 };
139
140 /*
141 *
142 */
143 PartitionEntry::PartitionEntry(int partnum, const char *aName, const char *aType, uint64 aOffset,
144 uint64 aLength)
145 {
146 mPartNum = partnum;
147 mName = strdup(aName);
148 mType = strdup(aType);
149 mOffset = aOffset;
150 mLength = aLength;
151 mBootMethod = BM_none;
152 mInstantiateBootFile = NULL;
153 mInstantiateBootFilePrivData = NULL;
154 mInstantiateFileSystem = NULL;
155 mBootImageLoadAddr = 0;
156 mBootImageEntrypoint = 0;
157 }
158
159 PartitionEntry::~PartitionEntry()
160 {
161 if (mInstantiateBootFilePrivData) free(mInstantiateBootFilePrivData);
162 free(mName);
163 free(mType);
164 }
165
166 /*
167 *
168 */
169 PartitionMap::PartitionMap(File *aDevice, uint aDeviceBlocksize)
170 {
171 mEntries = new Array(true);
172 mDevice = aDevice;
173 mDeviceBlocksize = aDeviceBlocksize;
174 addPartition(-1, "raw disk", "raw", 0, 0);
175 }
176
177 PartitionMap::~PartitionMap()
178 {
179 delete mEntries;
180 }
181
182 Enumerator *PartitionMap::getPartitions()
183 {
184 return mEntries;
185 }
186
187 void PartitionMap::getType(String &result)
188 {
189 result = "raw";
190 }
191
192 PartitionEntry *PartitionMap::addPartition(int partnum, const char *name, const char *type, uint64 offset, uint64 length)
193 {
194 PartitionEntry *e = new PartitionEntry(partnum, name, type, offset, length);
195 mEntries->insert(e);
196 return e;
197 }
198
199 /***/
200 struct FDiskInstantiateBootFilePrivData {
201 FileOfs mStart;
202 FileOfs mLen;
203 };
204
205 static File *FDiskInstantiateBootFile(File *aDevice, void *priv)
206 {
207 FDiskInstantiateBootFilePrivData *p = (FDiskInstantiateBootFilePrivData*)priv;
208 return new CroppedFile(aDevice, true, p->mStart, p->mLen);
209 }
210
211 /*
212 *
213 */
214 PartitionMapFDisk::PartitionMapFDisk(File *aDevice, uint aDeviceBlocksize)
215 :PartitionMap(aDevice, aDeviceBlocksize)
216 {
217 byte buffer[IDE_MAX_BLOCK_SIZE];
218 FDiskPartition *fdisk_part = (FDiskPartition *)&buffer[0x1be];
219
220 uint blocksize = aDeviceBlocksize;
221 if (blocksize <= 1) blocksize = 512;
222 aDevice->seek(0);
223 if (aDevice->read(buffer, blocksize) != blocksize) throw Exception();
224
225 IO_PROM_FS_TRACE("# boot head sect cyl. type head sect cyl. start size\n");
226 // IO_PROM_FS_TRACE("1 12 12 12 12 12 12 12 12 1234 1234\n");
227
228 for (int partition = 1; partition <= 4; partition++, fdisk_part++) {
229 createHostStructx(fdisk_part, sizeof *fdisk_part, FDiskPartition_struct, little_endian);
230
231 IO_PROM_FS_TRACE("%d %02x %02x %02x %02x %02x %02x %02x %02x %04lx %04lx\n",
232 partition,
233 fdisk_part->boot_ind,
234 fdisk_part->head, fdisk_part->sector, fdisk_part->cyl,
235 fdisk_part->sys_ind,
236 fdisk_part->end_head, fdisk_part->end_sector, fdisk_part->end_cyl,
237 fdisk_part->start, fdisk_part->size);
238
239 // FIXME: add extended partition support here
240
241 char *type;
242 switch (fdisk_part->sys_ind) {
243
244 case 0x00:
245 type = NULL;
246 break;
247 case LINUX_PARTITION:
248 case LINUX_NATIVE:
249 type = "Linux";
250 break;
251 case LINUX_SWAP:
252 type = "swap";
253 break;
254 default:
255 IO_PROM_FS_TRACE("Found unknown partition type: %02x\n",fdisk_part->sys_ind);
256 type = "unknown";
257 break;
258 }
259
260 char name[20];
261 ht_snprintf(name, sizeof name, "partition %d", partition);
262
263 if (type != NULL) {
264 PartitionEntry *partEnt = addPartition(partition, name, type,
265 fdisk_part->start * blocksize,
266 fdisk_part->size * blocksize);
267
268 if (fdisk_part->boot_ind & ACTIVE_FLAG)
269 {
270 partEnt->mBootMethod = BM_chrp;
271
272 FDiskInstantiateBootFilePrivData *priv =
273 (FDiskInstantiateBootFilePrivData*)
274 malloc(sizeof (FDiskInstantiateBootFilePrivData));
275 priv->mStart = fdisk_part->start * blocksize;
276 priv->mLen = fdisk_part->size * blocksize;
277
278 partEnt->mInstantiateBootFile = FDiskInstantiateBootFile;
279 partEnt->mInstantiateBootFilePrivData = priv;
280 partEnt->mInstantiateFileSystem = NULL;
281 }
282 }
283 }
284 }
285
286 void PartitionMapFDisk::getType(String &result)
287 {
288 result = "fdisk";
289 }
290
291 PartitionMapFDiskSingle::PartitionMapFDiskSingle(File *aDevice, uint aDeviceBlocksize, const char *type)
292 :PartitionMap(aDevice, aDeviceBlocksize)
293 {
294 uint64 offset = 0;
295 uint64 length = aDevice->getSize();
296
297 PartitionEntry *partEnt = addPartition(1, "unknown", type, offset, length);
298
299 FDiskInstantiateBootFilePrivData *priv =
300 (FDiskInstantiateBootFilePrivData*)
301 malloc(sizeof (FDiskInstantiateBootFilePrivData));
302 priv->mStart = offset;
303 priv->mLen = length;
304
305 partEnt->mBootMethod = BM_chrp;
306 partEnt->mInstantiateBootFile = FDiskInstantiateBootFile;
307 partEnt->mInstantiateBootFilePrivData = priv;
308 partEnt->mInstantiateFileSystem = NULL;
309
310 }
311
312 void PartitionMapFDiskSingle::getType(String &result)
313 {
314 result = "fdisk";
315 }
316
317 /***/
318 struct RawInstantiateBootFilePrivData {
319 FileOfs mStart;
320 FileOfs mLen;
321 };
322
323 static File *RawInstantiateBootFile(File *aDevice, void *priv)
324 {
325 RawInstantiateBootFilePrivData *p = (RawInstantiateBootFilePrivData*)priv;
326 return new CroppedFile(aDevice, true, p->mStart, p->mLen);
327 }
328
329 /***/
330 PartitionMapApple::PartitionMapApple(File *aDevice, uint aDeviceBlocksize)
331 :PartitionMap(aDevice, aDeviceBlocksize)
332 {
333 byte buffer[IDE_MAX_BLOCK_SIZE];
334 ApplePartition *apple_part = (ApplePartition *)&buffer;
335 uint blocksize = mDeviceBlocksize;
336 /*if (blocksize <= 1)*/ blocksize = 512;
337 aDevice->seek(0);
338 if (aDevice->read(buffer, blocksize) != blocksize) throw Exception();
339
340 createHostStructx(apple_part, sizeof *apple_part, ApplePartition_struct, big_endian);
341
342 if (apple_part->signature != APPLE_DRIVER_MAGIC) throw Exception();
343
344 IO_PROM_FS_TRACE("New Apple partition map, (physical) blocksize %d/0x%08x\n", blocksize, blocksize);
345 int map_size = 1;
346 IO_PROM_FS_TRACE("name type status start +data datasize +boot bootsize bootload bootentry\n");
347 // IO_PROM_FS_TRACE("0123456789123456 0123456789123456 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678\n");
348 for (int block = 1; block < map_size + 1; block++) {
349 aDevice->seek(block*blocksize);
350 if (aDevice->read(buffer, blocksize) != blocksize) continue;
351
352 createHostStructx(apple_part, sizeof *apple_part, ApplePartition_struct, big_endian);
353
354 if (apple_part->signature != APPLE_PARTITION_MAGIC) throw Exception();
355
356 if (block == 1) map_size = apple_part->map_count;
357
358 PartitionEntry *partEnt = addPartition(block, apple_part->name, apple_part->type,
359 (apple_part->start_block+apple_part->data_start) * blocksize,
360 apple_part->data_count * blocksize);
361
362 IO_PROM_FS_TRACE("%-16s %-16s %08x %08x %08x %08x %08x %08x %08x %08x\n",
363 apple_part->name,
364 apple_part->type,
365 apple_part->status,
366 apple_part->start_block*blocksize,
367 apple_part->data_start*blocksize,
368 apple_part->data_count*blocksize,
369 apple_part->boot_start*blocksize,
370 apple_part->boot_size,
371 apple_part->boot_load,
372 apple_part->boot_entry);
373
374 // Try HFS
375 if (tryBootHFS(aDevice, blocksize, apple_part->start_block*blocksize, partEnt))
376 continue;
377 // Try HFS+
378 if (tryBootHFSPlus(aDevice, blocksize, apple_part->start_block*blocksize, partEnt))
379 continue;
380 // Try boot via partition info.
381 if (apple_part->boot_size && apple_part->boot_load && apple_part->boot_entry) {
382 partEnt->mBootMethod = BM_direct;
383
384 RawInstantiateBootFilePrivData *priv =
385 (RawInstantiateBootFilePrivData*)
386 malloc(sizeof (RawInstantiateBootFilePrivData));
387 priv->mStart = apple_part->start_block*blocksize
388 + apple_part->boot_start*blocksize;
389 priv->mLen = apple_part->boot_size;
390
391 partEnt->mInstantiateBootFile = RawInstantiateBootFile;
392 partEnt->mInstantiateBootFilePrivData = priv;
393 partEnt->mInstantiateFileSystem = NULL;
394
395 partEnt->mBootImageLoadAddr = apple_part->boot_load;
396 partEnt->mBootImageEntrypoint = apple_part->boot_entry;
397 continue;
398 }
399 }
400 }
401
402 void PartitionMapApple::getType(String &result)
403 {
404 result = "apple";
405 }
406
407 PartitionMapAppleSingle::PartitionMapAppleSingle(File *aDevice, uint aDeviceBlocksize, const char *type)
408 :PartitionMap(aDevice, aDeviceBlocksize)
409 {
410 uint64 offset = 0;
411 uint64 length = aDevice->getSize();
412
413 PartitionEntry *partEnt = addPartition(1, "unknown", type, offset, length);
414
415 if (tryBootHFS(aDevice, aDeviceBlocksize, offset, partEnt))
416 ;
417 else if (tryBootHFSPlus(aDevice, aDeviceBlocksize, offset, partEnt))
418 ;
419 }
420
421 void PartitionMapAppleSingle::getType(String &result)
422 {
423 result = "apple";
424 }
425
426 /*
427 *
428 */
429 PartitionMap *partitions_get_map(File *aDevice, uint aDeviceBlocksize)
430 {
431 byte buffer[IDE_MAX_BLOCK_SIZE];
432 byte signature[2];
433 uint blocksize = aDeviceBlocksize;
434 if (blocksize <= 1) blocksize = 512;
435 aDevice->seek(0);
436 if (aDevice->read(buffer, blocksize) != blocksize) {
437 IO_PROM_FS_TRACE("device read failed while probing partitions\n");
438 return new PartitionMap(aDevice, aDeviceBlocksize);
439 }
440 // look for partition maps
441 if (blocksize >= 2 && buffer[0] == 0x45 && buffer[1] == 0x52) {
442 IO_PROM_FS_TRACE("this looks like a Apple partition map to me...\n");
443
444 try {
445 return new PartitionMapApple(aDevice, aDeviceBlocksize);
446 } catch (const Exception &e) {
447 String s;
448 e.reason(s);
449 IO_PROM_FS_TRACE("exception probing Apple partitions: %y\n", &s);
450 }
451 }
452 if (blocksize >= 512 && buffer[510] == 0x55 && buffer[511] == 0xaa) {
453 IO_PROM_FS_TRACE("this looks like a FDisk partition map to me...\n");
454
455 try {
456 return new PartitionMapFDisk(aDevice, aDeviceBlocksize);
457 } catch (const Exception &e) {
458 String s;
459 e.reason(s);
460 IO_PROM_FS_TRACE("exception probing fdisk partitions: %y\n", &s);
461 }
462 }
463 // look for raw partitions
464 aDevice->seek(0x400);
465 if (aDevice->read(signature, 2) == 2) {
466 if (signature[0] == 0x42 && signature[1] == 0x44) {
467 IO_PROM_FS_TRACE("this looks like a single HFS partition to me...\n");
468
469 try {
470 return new PartitionMapAppleSingle(aDevice, aDeviceBlocksize, "Apple_HFS");
471 } catch (const Exception &e) {
472 String s;
473 e.reason(s);
474 IO_PROM_FS_TRACE("exception probing HFS partition: %y\n", &s);
475 }
476 }
477 if (signature[0] == 0x48 && (signature[1] == 0x2b || signature[2] == 0x58)) {
478 IO_PROM_FS_TRACE("this looks like a single HFS+ partition to me...\n");
479
480 try {
481 return new PartitionMapAppleSingle(aDevice, aDeviceBlocksize, "Apple_HFS");
482 } catch (const Exception &e) {
483 String s;
484 e.reason(s);
485 IO_PROM_FS_TRACE("exception probing HFS+ partition: %y\n", &s);
486 }
487 }
488 }
489 aDevice->seek(0x438);
490 if (aDevice->read(signature, 2) == 2) {
491 if (signature[0] == 0x53 && signature[1] == 0xef) {
492 IO_PROM_FS_TRACE("this looks like a single ext2 partition to me...\n");
493
494 try {
495 return new PartitionMapFDiskSingle(aDevice, aDeviceBlocksize, "ext2");
496 } catch (const Exception &e) {
497 String s;
498 e.reason(s);
499 IO_PROM_FS_TRACE("exception probing ext2 partition: %y\n", &s);
500 }
501 }
502 }
503
504 IO_PROM_FS_TRACE("probe found no partitions in %d bytes block\n",blocksize);
505 return new PartitionMap(aDevice, aDeviceBlocksize);
506 }

  ViewVC Help
Powered by ViewVC 1.1.26