]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOStorage/IOFDiskPartitionScheme.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Families / IOStorage / IOFDiskPartitionScheme.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <IOKit/assert.h>
24 #include <IOKit/IOBufferMemoryDescriptor.h>
25 #include <IOKit/IOLib.h>
26 #include <IOKit/storage/IOFDiskPartitionScheme.h>
27 #include <libkern/OSByteOrder.h>
28
29 #define super IOPartitionScheme
30 OSDefineMetaClassAndStructors(IOFDiskPartitionScheme, IOPartitionScheme);
31
32 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33 // Notes
34 //
35 // o the on-disk structure's fields are: 16-bit packed, little-endian formatted
36 // o the relsect and numsect block values assume the drive's natural block size
37 // o the relsect block value is:
38 // o for data partitions:
39 // o relative to the FDisk map that defines the partition
40 // o for extended partitions defined in the root-level FDisk map:
41 // o relative to the FDisk map that defines the partition (start of disk)
42 // o for extended partitions defined in a second-level or deeper FDisk map:
43 // o relative to the second-level FDisk map, regardless of depth
44 // o the valid extended partition types are: 0x05, 0x0F, 0x85
45 // o there should be no more than one extended partition defined per FDisk map
46 //
47
48 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49
50 #define kIOFDiskPartitionSchemeContentTable "Content Table"
51
52 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53
54 bool IOFDiskPartitionScheme::init(OSDictionary * properties = 0)
55 {
56 //
57 // Initialize this object's minimal state.
58 //
59
60 // State our assumptions.
61
62 assert(sizeof(fdisk_part) == 16); // (compiler/platform check)
63 assert(sizeof(disk_blk0) == 512); // (compiler/platform check)
64
65 // Ask our superclass' opinion.
66
67 if ( super::init(properties) == false ) return false;
68
69 // Initialize our state.
70
71 _partitions = 0;
72
73 return true;
74 }
75
76 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
77
78 void IOFDiskPartitionScheme::free()
79 {
80 //
81 // Free all of this object's outstanding resources.
82 //
83
84 if ( _partitions ) _partitions->release();
85
86 super::free();
87 }
88
89 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
90
91 IOService * IOFDiskPartitionScheme::probe(IOService * provider, SInt32 * score)
92 {
93 //
94 // Determine whether the provider media contains an FDisk partition map.
95 //
96
97 // State our assumptions.
98
99 assert(OSDynamicCast(IOMedia, provider));
100
101 // Ask our superclass' opinion.
102
103 if ( super::probe(provider, score) == 0 ) return 0;
104
105 // Scan the provider media for an FDisk partition map.
106
107 _partitions = scan(score);
108
109 // There might be an FDisk partition scheme on disk with boot code, but with
110 // no partitions defined. We don't consider this a match and return failure
111 // from probe.
112
113 if ( _partitions && _partitions->getCount() == 0 )
114 {
115 _partitions->release();
116 _partitions = 0;
117 }
118
119 return ( _partitions ) ? this : 0;
120 }
121
122 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123
124 bool IOFDiskPartitionScheme::start(IOService * provider)
125 {
126 //
127 // Publish the new media objects which represent our partitions.
128 //
129
130 IOMedia * partition;
131 OSIterator * partitionIterator;
132
133 // State our assumptions.
134
135 assert(_partitions);
136
137 // Ask our superclass' opinion.
138
139 if ( super::start(provider) == false ) return false;
140
141 // Attach and register the new media objects representing our partitions.
142
143 partitionIterator = OSCollectionIterator::withCollection(_partitions);
144 if ( partitionIterator == 0 ) return false;
145
146 while ( (partition = (IOMedia *) partitionIterator->getNextObject()) )
147 {
148 if ( partition->attach(this) )
149 {
150 partition->registerService();
151 }
152 }
153
154 partitionIterator->release();
155
156 return true;
157 }
158
159 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
160
161 OSSet * IOFDiskPartitionScheme::scan(SInt32 * score)
162 {
163 //
164 // Scan the provider media for an FDisk partition map. Returns the set
165 // of media objects representing each of the partitions (the retain for
166 // the set is passed to the caller), or null should no partition map be
167 // found. The default probe score can be adjusted up or down, based on
168 // the confidence of the scan.
169 //
170
171 IOBufferMemoryDescriptor * buffer = 0;
172 UInt32 bufferSize = 0;
173 UInt32 fdiskBlock = 0;
174 UInt32 fdiskBlockExtn = 0;
175 UInt32 fdiskBlockNext = 0;
176 UInt32 fdiskID = 0;
177 disk_blk0 * fdiskMap = 0;
178 IOMedia * media = getProvider();
179 UInt64 mediaBlockSize = media->getPreferredBlockSize();
180 bool mediaIsOpen = false;
181 OSSet * partitions = 0;
182 IOReturn status = kIOReturnError;
183
184 // Determine whether this media is formatted.
185
186 if ( media->isFormatted() == false ) goto scanErr;
187
188 // Determine whether this media has an appropriate block size.
189
190 if ( (mediaBlockSize % sizeof(disk_blk0)) ) goto scanErr;
191
192 // Allocate a buffer large enough to hold one map, rounded to a media block.
193
194 bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize);
195 buffer = IOBufferMemoryDescriptor::withCapacity(
196 /* capacity */ bufferSize,
197 /* withDirection */ kIODirectionIn );
198 if ( buffer == 0 ) goto scanErr;
199
200 // Allocate a set to hold the set of media objects representing partitions.
201
202 partitions = OSSet::withCapacity(4);
203 if ( partitions == 0 ) goto scanErr;
204
205 // Open the media with read access.
206
207 mediaIsOpen = media->open(this, 0, kIOStorageAccessReader);
208 if ( mediaIsOpen == false ) goto scanErr;
209
210 // Scan the media for FDisk partition map(s).
211
212 do
213 {
214 // Read the next FDisk map into our buffer.
215
216 ///m:2333367:workaround:commented:start
217 // status = media->read(this, fdiskBlock * mediaBlockSize, buffer);
218 ///m:2333367:workaround:commented:stop
219 ///m:2333367:workaround:added:start
220 status = media->IOStorage::read(this, fdiskBlock * mediaBlockSize, buffer);
221 ///m:2333367:workaround:added:stop
222 if ( status != kIOReturnSuccess ) goto scanErr;
223
224 fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy();
225
226 // Determine whether the partition map signature is present.
227
228 if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
229 {
230 goto scanErr;
231 }
232
233 // Scan for valid partition entries in the partition map.
234
235 fdiskBlockNext = 0;
236
237 for ( unsigned index = 0; index < DISK_NPART; index++ )
238 {
239 // Determine whether this is an extended (vs. data) partition.
240
241 if ( isPartitionExtended(fdiskMap->parts + index) ) // (extended)
242 {
243 // If peer extended partitions exist, we accept only the first.
244
245 if ( fdiskBlockNext == 0 ) // (no peer extended partition)
246 {
247 fdiskBlockNext = fdiskBlockExtn +
248 OSSwapLittleToHostInt32(
249 /* data */ fdiskMap->parts[index].relsect );
250
251 if ( fdiskBlockNext * mediaBlockSize >= media->getSize() )
252 {
253 fdiskBlockNext = 0; // (exceeds confines of media)
254 }
255 }
256 }
257 else if ( isPartitionUsed(fdiskMap->parts + index) ) // (data)
258 {
259 // Prepare this partition's ID.
260
261 fdiskID = ( fdiskBlock == 0 ) ? (index + 1) : (fdiskID + 1);
262
263 // Determine whether the partition is corrupt (fatal).
264
265 if ( isPartitionCorrupt(
266 /* partition */ fdiskMap->parts + index,
267 /* partitionID */ fdiskID,
268 /* fdiskBlock */ fdiskBlock ) )
269 {
270 goto scanErr;
271 }
272
273 // Determine whether the partition is invalid (skipped).
274
275 if ( isPartitionInvalid(
276 /* partition */ fdiskMap->parts + index,
277 /* partitionID */ fdiskID,
278 /* fdiskBlock */ fdiskBlock ) )
279 {
280 continue;
281 }
282
283 // Create a media object to represent this partition.
284
285 IOMedia * newMedia = instantiateMediaObject(
286 /* partition */ fdiskMap->parts + index,
287 /* partitionID */ fdiskID,
288 /* fdiskBlock */ fdiskBlock );
289
290 if ( newMedia )
291 {
292 partitions->setObject(newMedia);
293 newMedia->release();
294 }
295 }
296 }
297
298 // Prepare for first extended partition, if any.
299
300 if ( fdiskBlock == 0 )
301 {
302 fdiskID = DISK_NPART;
303 fdiskBlockExtn = fdiskBlockNext;
304 }
305
306 } while ( (fdiskBlock = fdiskBlockNext) );
307
308 // Release our resources.
309
310 media->close(this);
311 buffer->release();
312
313 return partitions;
314
315 scanErr:
316
317 // Release our resources.
318
319 if ( mediaIsOpen ) media->close(this);
320 if ( partitions ) partitions->release();
321 if ( buffer ) buffer->release();
322
323 return 0;
324 }
325
326 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
327
328 bool IOFDiskPartitionScheme::isPartitionExtended(fdisk_part * partition)
329 {
330 //
331 // Ask whether the given partition is extended.
332 //
333
334 return ( partition->systid == 0x05 ||
335 partition->systid == 0x0F ||
336 partition->systid == 0x85 );
337 }
338
339 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
340
341 bool IOFDiskPartitionScheme::isPartitionUsed(fdisk_part * partition)
342 {
343 //
344 // Ask whether the given partition is used.
345 //
346
347 return ( partition->systid != 0 && partition->numsect != 0 );
348 }
349
350 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
351
352 bool IOFDiskPartitionScheme::isPartitionCorrupt(
353 fdisk_part * /* partition */ ,
354 UInt32 /* partitionID */ ,
355 UInt32 /* fdiskBlock */ )
356 {
357 //
358 // Ask whether the given partition appears to be corrupt. A partition that
359 // is corrupt will cause the failure of the FDisk partition map recognition
360 // altogether.
361 //
362
363 return false;
364 }
365
366 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
367
368 bool IOFDiskPartitionScheme::isPartitionInvalid( fdisk_part * partition,
369 UInt32 partitionID,
370 UInt32 fdiskBlock )
371 {
372 //
373 // Ask whether the given partition appears to be invalid. A partition that
374 // is invalid will cause it to be skipped in the scan, but will not cause a
375 // failure of the FDisk partition map recognition.
376 //
377
378 IOMedia * media = getProvider();
379 UInt64 mediaBlockSize = media->getPreferredBlockSize();
380 UInt64 partitionBase = 0;
381 UInt64 partitionSize = 0;
382
383 // Compute the relative byte position and size of the new partition.
384
385 partitionBase = OSSwapLittleToHostInt32(partition->relsect) + fdiskBlock;
386 partitionSize = OSSwapLittleToHostInt32(partition->numsect);
387 partitionBase *= mediaBlockSize;
388 partitionSize *= mediaBlockSize;
389
390 // Determine whether the partition starts at (or past) the end-of-media.
391
392 if ( partitionBase >= media->getSize() ) return true;
393
394 return false;
395 }
396
397 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
398
399 IOMedia * IOFDiskPartitionScheme::instantiateMediaObject(
400 fdisk_part * partition,
401 UInt32 partitionID,
402 UInt32 fdiskBlock )
403 {
404 //
405 // Instantiate a new media object to represent the given partition.
406 //
407
408 IOMedia * media = getProvider();
409 UInt64 mediaBlockSize = media->getPreferredBlockSize();
410 UInt64 partitionBase = 0;
411 char * partitionHint = 0;
412 UInt64 partitionSize = 0;
413
414 // Compute the relative byte position and size of the new partition.
415
416 partitionBase = OSSwapLittleToHostInt32(partition->relsect) + fdiskBlock;
417 partitionSize = OSSwapLittleToHostInt32(partition->numsect);
418 partitionBase *= mediaBlockSize;
419 partitionSize *= mediaBlockSize;
420
421 // Clip the size of the new partition if it extends past the end-of-media.
422
423 if ( partitionBase + partitionSize > media->getSize() )
424 {
425 partitionSize = media->getSize() - partitionBase;
426 }
427
428 // Look up a type for the new partition.
429
430 OSDictionary * hintTable = OSDynamicCast(
431 /* type */ OSDictionary,
432 /* instance */ getProperty(kIOFDiskPartitionSchemeContentTable) );
433
434 if ( hintTable )
435 {
436 char hintIndex[5];
437 OSString * hintValue;
438
439 sprintf(hintIndex, "0x%02X", partition->systid & 0xFF);
440
441 hintValue = OSDynamicCast(OSString, hintTable->getObject(hintIndex));
442
443 if ( hintValue ) partitionHint = (char *) hintValue->getCStringNoCopy();
444 }
445
446 // Create the new media object.
447
448 IOMedia * newMedia = instantiateDesiredMediaObject(
449 /* partition */ partition,
450 /* partitionID */ partitionID,
451 /* fdiskBlock */ fdiskBlock );
452
453 if ( newMedia )
454 {
455 if ( newMedia->init(
456 /* base */ partitionBase,
457 /* size */ partitionSize,
458 /* preferredBlockSize */ mediaBlockSize,
459 /* isEjectable */ media->isEjectable(),
460 /* isWhole */ false,
461 /* isWritable */ media->isWritable(),
462 /* contentHint */ partitionHint ) )
463 {
464 // Set a name for this partition.
465
466 char name[24];
467 sprintf(name, "Untitled %ld", partitionID);
468 newMedia->setName(name);
469
470 // Set a location value (the partition number) for this partition.
471
472 char location[12];
473 sprintf(location, "%ld", partitionID);
474 newMedia->setLocation(location);
475
476 // Set the "Partition ID" key for this partition.
477
478 newMedia->setProperty(kIOMediaPartitionIDKey, partitionID, 32);
479 }
480 else
481 {
482 newMedia->release();
483 newMedia = 0;
484 }
485 }
486
487 return newMedia;
488 }
489
490 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
491
492 IOMedia * IOFDiskPartitionScheme::instantiateDesiredMediaObject(
493 fdisk_part * partition,
494 UInt32 partitionID,
495 UInt32 fdiskBlock )
496 {
497 //
498 // Allocate a new media object (called from instantiateMediaObject).
499 //
500
501 return new IOMedia;
502 }
503
504 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
505
506 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 0);
507
508 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
509
510 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 1);
511
512 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
513
514 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 2);
515
516 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
517
518 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 3);
519
520 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
521
522 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 4);
523
524 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
525
526 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 5);
527
528 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
529
530 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 6);
531
532 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
533
534 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 7);
535
536 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
537
538 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 8);
539
540 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
541
542 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 9);
543
544 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
545
546 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 10);
547
548 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
549
550 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 11);
551
552 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
553
554 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 12);
555
556 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
557
558 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 13);
559
560 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
561
562 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 14);
563
564 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
565
566 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 15);