IOApplePartitionScheme.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOLib.h>
#include <IOKit/storage/IOApplePartitionScheme.h>
#include <libkern/OSByteOrder.h>
#define super IOPartitionScheme
OSDefineMetaClassAndStructors(IOApplePartitionScheme, IOPartitionScheme);
#define kIOApplePartitionSchemeContentTable "Content Table"
bool IOApplePartitionScheme::init(OSDictionary * properties = 0)
{
assert(sizeof(dpme) == 512); assert(sizeof(DDMap) == 8); assert(sizeof(Block0) == 512);
if (super::init(properties) == false) return false;
_partitions = 0;
return true;
}
void IOApplePartitionScheme::free()
{
if ( _partitions ) _partitions->release();
super::free();
}
IOService * IOApplePartitionScheme::probe(IOService * provider, SInt32 * score)
{
assert(OSDynamicCast(IOMedia, provider));
if (super::probe(provider, score) == 0) return 0;
_partitions = scan(score);
return ( _partitions ) ? this : 0;
}
bool IOApplePartitionScheme::start(IOService * provider)
{
IOMedia * partition;
OSIterator * partitionIterator;
assert(_partitions);
if ( super::start(provider) == false ) return false;
partitionIterator = OSCollectionIterator::withCollection(_partitions);
if ( partitionIterator == 0 ) return false;
while ( (partition = (IOMedia *) partitionIterator->getNextObject()) )
{
if ( partition->attach(this) )
{
attachMediaObjectToDeviceTree(partition);
partition->registerService();
}
}
partitionIterator->release();
return true;
}
void IOApplePartitionScheme::stop(IOService * provider)
{
IOMedia * partition;
OSIterator * partitionIterator;
assert(_partitions);
partitionIterator = OSCollectionIterator::withCollection(_partitions);
if ( partitionIterator )
{
while ( (partition = (IOMedia *) partitionIterator->getNextObject()) )
{
detachMediaObjectFromDeviceTree(partition);
}
partitionIterator->release();
}
super::stop(provider);
}
OSSet * IOApplePartitionScheme::scan(SInt32 * score)
{
IOBufferMemoryDescriptor * buffer = 0;
UInt32 bufferReadAt = 0;
UInt32 bufferSize = 0;
UInt32 dpmeBlockSize = 0;
UInt32 dpmeCount = 0;
UInt32 dpmeID = 0;
dpme * dpmeMap = 0;
UInt32 dpmeMaxCount = 0;
bool dpmeOldSchool = false;
Block0 * driverMap = 0;
IOMedia * media = getProvider();
UInt64 mediaBlockSize = media->getPreferredBlockSize();
bool mediaIsOpen = false;
OSSet * partitions = 0;
IOReturn status = kIOReturnError;
if ( media->isFormatted() == false ) goto scanErr;
if ( (mediaBlockSize % sizeof(dpme)) ) goto scanErr;
bufferSize = IORound(max(sizeof(Block0), sizeof(dpme)), mediaBlockSize);
buffer = IOBufferMemoryDescriptor::withCapacity(
bufferSize,
kIODirectionIn );
if ( buffer == 0 ) goto scanErr;
partitions = OSSet::withCapacity(8);
if ( partitions == 0 ) goto scanErr;
mediaIsOpen = media->open(this, 0, kIOStorageAccessReader);
if ( mediaIsOpen == false ) goto scanErr;
bufferReadAt = 0;
status = media->IOStorage::read(this, bufferReadAt, buffer);
if ( status != kIOReturnSuccess ) goto scanErr;
driverMap = (Block0 *) buffer->getBytesNoCopy();
dpmeBlockSize = mediaBlockSize;
if ( driverMap->sbSig == BLOCK0_SIGNATURE )
{
dpmeBlockSize = driverMap->sbBlkSize;
*score += 2000;
}
if ( dpmeBlockSize == 2048 )
{
if ( bufferSize >= sizeof(Block0) + sizeof(dpme) ) {
dpmeMap = (dpme *) (driverMap + 1);
}
else {
bufferReadAt = sizeof(dpme);
status = media->IOStorage::read(this, bufferReadAt, buffer);
if ( status != kIOReturnSuccess ) goto scanErr;
dpmeMap = (dpme *) buffer->getBytesNoCopy();
}
if (OSSwapBigToHostInt16(dpmeMap->dpme_signature) == DPME_SIGNATURE)
{
dpmeBlockSize = sizeof(dpme); dpmeOldSchool = true;
}
}
for ( dpmeID = 1, dpmeCount = 1; dpmeID <= dpmeCount; dpmeID++ )
{
UInt32 partitionBlockSize = dpmeBlockSize;
if ( dpmeID * dpmeBlockSize + sizeof(dpme) > bufferReadAt + bufferSize )
{
bufferReadAt = dpmeID * dpmeBlockSize;
status = media->IOStorage::read(this, bufferReadAt, buffer);
if ( status != kIOReturnSuccess ) goto scanErr;
}
dpmeMap = (dpme *) ( ((UInt8 *) buffer->getBytesNoCopy()) +
(dpmeID * dpmeBlockSize) - bufferReadAt );
if ( OSSwapBigToHostInt16(dpmeMap->dpme_signature) != DPME_SIGNATURE )
{
goto scanErr;
}
if ( !strcmp(dpmeMap->dpme_type, "Apple_partition_map") ||
!strcmp(dpmeMap->dpme_type, "Apple_Partition_Map") ||
!strcmp(dpmeMap->dpme_type, "Apple_patition_map" ) )
{
dpmeCount = OSSwapBigToHostInt32(dpmeMap->dpme_map_entries);
dpmeMaxCount = OSSwapBigToHostInt32(dpmeMap->dpme_pblocks);
}
else if ( dpmeCount == 1 )
{
dpmeCount = OSSwapBigToHostInt32(dpmeMap->dpme_map_entries);
}
if ( dpmeOldSchool && (dpmeID % 4) == 0 )
{
if ( !strcmp(dpmeMap->dpme_type, "Apple_Driver" ) ||
!strcmp(dpmeMap->dpme_type, "Apple_Driver43" ) ||
!strcmp(dpmeMap->dpme_type, "Apple_Driver43_CD" ) ||
!strcmp(dpmeMap->dpme_type, "Apple_Driver_ATA" ) ||
!strcmp(dpmeMap->dpme_type, "Apple_Driver_ATAPI") ||
!strcmp(dpmeMap->dpme_type, "Apple_Patches" ) )
{
partitionBlockSize = 2048;
}
}
if ( isPartitionCorrupt(
dpmeMap,
dpmeID,
partitionBlockSize ) )
{
goto scanErr;
}
if ( isPartitionInvalid(
dpmeMap,
dpmeID,
partitionBlockSize ) )
{
continue;
}
IOMedia * newMedia = instantiateMediaObject(
dpmeMap,
dpmeID,
partitionBlockSize );
if ( newMedia )
{
partitions->setObject(newMedia);
newMedia->release();
}
}
if ( dpmeMaxCount == 0 ) goto scanErr;
media->close(this);
buffer->release();
return partitions;
scanErr:
if ( mediaIsOpen ) media->close(this);
if ( partitions ) partitions->release();
if ( buffer ) buffer->release();
return 0;
}
bool IOApplePartitionScheme::isPartitionCorrupt(
dpme * ,
UInt32 ,
UInt32 )
{
return false;
}
bool IOApplePartitionScheme::isPartitionInvalid( dpme * partition,
UInt32 partitionID,
UInt32 partitionBlockSize )
{
IOMedia * media = getProvider();
UInt64 partitionBase = 0;
UInt64 partitionSize = 0;
partitionBase = OSSwapBigToHostInt32(partition->dpme_pblock_start);
partitionSize = OSSwapBigToHostInt32(partition->dpme_pblocks);
partitionBase *= partitionBlockSize;
partitionSize *= partitionBlockSize;
if ( partitionSize == 0 ) return true;
if ( partitionBase >= media->getSize() ) return true;
return false;
}
IOMedia * IOApplePartitionScheme::instantiateMediaObject(
dpme * partition,
UInt32 partitionID,
UInt32 partitionBlockSize )
{
IOMedia * media = getProvider();
UInt64 mediaBlockSize = media->getPreferredBlockSize();
UInt64 partitionBase = 0;
char * partitionHint = partition->dpme_type;
bool partitionIsWritable = media->isWritable();
char * partitionName = partition->dpme_name;
UInt64 partitionSize = 0;
partitionBase = OSSwapBigToHostInt32(partition->dpme_pblock_start);
partitionSize = OSSwapBigToHostInt32(partition->dpme_pblocks);
partitionBase *= partitionBlockSize;
partitionSize *= partitionBlockSize;
if ( partitionBase + partitionSize > media->getSize() )
{
partitionSize = media->getSize() - partitionBase;
}
OSDictionary * hintTable = OSDynamicCast(
OSDictionary,
getProperty(kIOApplePartitionSchemeContentTable) );
if ( hintTable )
{
OSString * hintValue = OSDynamicCast(
OSString,
hintTable->getObject(partitionHint) );
if ( hintValue ) partitionHint = (char *) hintValue->getCStringNoCopy();
}
while ( *partitionName == ' ' ) { partitionName++; }
if ( *partitionName == 0 ) partitionName = 0;
if ( !strcmp(partitionHint, "Apple_Free") ) return 0;
if ( !strcmp(partition->dpme_type, "Apple_partition_map") ||
!strcmp(partition->dpme_type, "Apple_Partition_Map") ||
!strcmp(partition->dpme_type, "Apple_patition_map" ) ||
( ((partition->dpme_flags & DPME_FLAGS_WRITABLE) == 0) &&
((partition->dpme_flags & DPME_FLAGS_VALID ) != 0) ) )
{
partitionIsWritable = false;
}
IOMedia * newMedia = instantiateDesiredMediaObject(
partition,
partitionID,
partitionBlockSize );
if ( newMedia )
{
if ( newMedia->init(
partitionBase,
partitionSize,
mediaBlockSize,
media->isEjectable(),
false,
partitionIsWritable,
partitionHint ) )
{
char name[24];
sprintf(name, "Untitled %ld", partitionID);
newMedia->setName(partitionName ? partitionName : name);
char location[12];
sprintf(location, "%ld", partitionID);
newMedia->setLocation(location);
newMedia->setProperty(kIOMediaPartitionIDKey, partitionID, 32);
}
else
{
newMedia->release();
newMedia = 0;
}
}
return newMedia;
}
IOMedia * IOApplePartitionScheme::instantiateDesiredMediaObject(
dpme * partition,
UInt32 partitionID,
UInt32 partitionBlockSize )
{
return new IOMedia;
}
bool IOApplePartitionScheme::attachMediaObjectToDeviceTree( IOMedia * media )
{
IOService * service;
SInt32 unit = -1;
for ( service = this; service; service = service->getProvider() )
{
OSNumber * number;
if ( (number = OSDynamicCast(OSNumber, service->getProperty("IOUnit"))))
{
unit = number->unsigned32BitValue();
}
if ( service->inPlane(gIODTPlane) )
{
IORegistryEntry * child;
IORegistryIterator * children;
if ( unit == -1 ) break;
children = IORegistryIterator::iterateOver(service, gIODTPlane);
if ( children == 0 ) break;
while ( (child = children->getNextObject()) )
{
const char * location = child->getLocation(gIODTPlane);
const char * name = child->getName(gIODTPlane);
if ( name == 0 || strcmp(name, "" ) != 0 ||
location == 0 || strchr(location, ':') == 0 )
{
child->detachAll(gIODTPlane);
}
}
children->release();
if ( media->attachToParent(service, gIODTPlane) )
{
char location[ sizeof("hhhhhhhh:dddddddddd") ];
sprintf(location, "%lx:", unit);
strcat(location, media->getLocation());
media->setLocation(location, gIODTPlane);
media->setName("", gIODTPlane);
return true;
}
break;
}
}
return false;
}
void IOApplePartitionScheme::detachMediaObjectFromDeviceTree( IOMedia * media )
{
IORegistryEntry * parent;
if ( (parent = media->getParentEntry(gIODTPlane)) )
{
media->detachFromParent(parent, gIODTPlane);
}
}
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 0);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 1);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 2);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 3);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 4);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 5);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 6);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 7);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 8);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 9);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 10);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 11);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 12);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 13);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 14);
OSMetaClassDefineReservedUnused(IOApplePartitionScheme, 15);