first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

@@ -0,0 +1,232 @@
/*
* Copyright (c) 2010-11 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
// =============================================================================
#include <stdint.h>
#include <IOKit/IOLib.h>
#include "AppleEffaceableNAND.h"
#include "effaceable_contract.h"
#include "effaceable_debug.h"
// =============================================================================
#define debug(...) dlogf((void*)0, __VA_ARGS__ )
// =============================================================================
#ifdef super
#undef super
#endif
#define super AppleEffaceableStorage
OSDefineMetaClassAndStructors(AppleEffaceableNAND, AppleEffaceableStorage);
// =============================================================================
bool
AppleEffaceableNAND::start(IOService *provider)
{
bool ok = false;
debug(INFO, "starting");
setupNandContract();
if (0 == (_partition = OSDynamicCast(IOFlashStoragePartition, provider))) {
debug(ERR, "provider is not an IOFlashStoragePartition");
} else if (!super::start(provider)) {
debug(ERR, "superclass unable to start");
} else {
debug(INIT, "started");
ok = true;
}
return ok;
}
// =============================================================================
effaceable_nand_hal_t *
AppleEffaceableNAND::nand(void)
{
return &_nand_hal;
}
void
AppleEffaceableNAND::setupDeviceContract(void)
{
startEffaceableNAND(device(), system(), nand(), storage());
}
// =============================================================================
AppleEffaceableNAND * context(effaceable_nand_hal_t * nand)
{
AppleEffaceableNAND * context;
// XXX assert instead?
if (0 == (context = (AppleEffaceableNAND *)nand->opaque))
panic("null context");
return context;
}
uint32_t getPageSizeHook(effaceable_nand_hal_t * nand)
{
return context(nand)->getPageSizeNand();
}
uint32_t getPageCountHook(effaceable_nand_hal_t * nand)
{
return context(nand)->getPageCountNand();
}
uint32_t getBlockCountHook(effaceable_nand_hal_t * nand)
{
return context(nand)->getBlockCountNand();
}
uint32_t getBankCountHook(effaceable_nand_hal_t * nand)
{
return context(nand)->getBankCountNand();
}
bool isBlockBadHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block)
{
return context(nand)->isBlockBadNand(bank, block);
}
EffaceableReturn eraseBlockHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block)
{
return context(nand)->eraseBlockNand(bank, block);
}
EffaceableReturn writePageHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block, uint32_t page, const void * buf, uint32_t length)
{
return context(nand)->writePageNand(bank, block, page, buf, length);
}
EffaceableReturn readPageHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block, uint32_t page, void * buf, uint32_t length)
{
return context(nand)->readPageNand(bank, block, page, buf, length);
}
bool requestPartitionTableDiffHook(effaceable_nand_hal_t * nand, void * buf, uint32_t length)
{
return context(nand)->requestPartitionTableDiffNand(buf, length);
}
bool providePartitionTableDiffHook(effaceable_nand_hal_t * nand, void * buf, uint32_t length)
{
return context(nand)->providePartitionTableDiffNand(buf, length);
}
// =============================================================================
void
AppleEffaceableNAND::setupNandContract(void)
{
nand()->opaque = this;
nand()->getPageSize = getPageSizeHook;
nand()->getPageCount = getPageCountHook;
nand()->getBlockCount = getBlockCountHook;
nand()->getBankCount = getBankCountHook;
nand()->isBlockBad = isBlockBadHook;
nand()->eraseBlock = eraseBlockHook;
nand()->writePage = writePageHook;
nand()->readPage = readPageHook;
nand()->requestPartitionTableDiff = requestPartitionTableDiffHook;
nand()->providePartitionTableDiff = providePartitionTableDiffHook;
}
uint32_t AppleEffaceableNAND::getPageSizeNand(void)
{
return (IOByteCount)_partition->getPageSize();
}
uint32_t AppleEffaceableNAND::getPageCountNand(void)
{
return _partition->getPagesPerBlock();
}
uint32_t AppleEffaceableNAND::getBlockCountNand(void)
{
return _partition->getBlockCount();
}
uint32_t AppleEffaceableNAND::getBankCountNand(void)
{
return _partition->getBankCount();
}
bool AppleEffaceableNAND::isBlockBadNand(uint32_t bank, uint32_t block)
{
return _partition->isBlockBad(bank, block);
}
EffaceableReturn AppleEffaceableNAND::eraseBlockNand(uint32_t bank, uint32_t block)
{
return efReturn(_partition->eraseBlock(bank, block));
}
EffaceableReturn AppleEffaceableNAND::writePageNand(uint32_t bank, uint32_t block, uint32_t page, const void * buf, uint32_t length)
{
IOReturn ok;
IOBufferMemoryDescriptor * bmd;
// XXX It's unfortunate that the IOBMD is necessary; think about how/where to clean it up.
bmd = IOBufferMemoryDescriptor::withBytes(buf, length, kIODirectionInOut, true);
if (0 == bmd)
panic("no memory");
ok = _partition->writePage(bank, block, page, bmd);
bmd->release();
return efReturn(ok);
}
EffaceableReturn AppleEffaceableNAND::readPageNand(uint32_t bank, uint32_t block, uint32_t page, void * buf, uint32_t length)
{
IOReturn ok;
IOBufferMemoryDescriptor * bmd;
// XXX It's unfortunate that the IOBMD is necessary; think about how/where to clean it up.
bmd = IOBufferMemoryDescriptor::withCapacity(length, kIODirectionInOut, true);
if (0 == bmd)
panic("no memory");
ok = _partition->readPage(bank, block, page, bmd);
if (kIOReturnSuccess == ok)
bmd->readBytes(0, buf, length);
bmd->release();
return efReturn(ok);
}
bool AppleEffaceableNAND::requestPartitionTableDiffNand(void * buf, uint32_t length)
{
return _partition->requestPartitionTableDiff(buf, length);
}
bool AppleEffaceableNAND::providePartitionTableDiffNand(void * buf, uint32_t length)
{
return _partition->providePartitionTableDiff(buf, length);
}
// =============================================================================
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-11 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef _APPLE_EFFACEABLE_NAND_H
#define _APPLE_EFFACEABLE_NAND_H
#include <IOKit/IOService.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/storage/flash/IOFlashStoragePartition.h>
#include "AppleEffaceableStorage.h"
#include "effaceable_contract.h"
class AppleEffaceableNAND : public AppleEffaceableStorage
{
OSDeclareDefaultStructors(AppleEffaceableNAND);
public:
virtual bool start(IOService * provider);
friend uint32_t getPageSizeHook(effaceable_nand_hal_t * nand);
friend uint32_t getPageCountHook(effaceable_nand_hal_t * nand);
friend uint32_t getBlockCountHook(effaceable_nand_hal_t * nand);
friend uint32_t getBankCountHook(effaceable_nand_hal_t * nand);
friend bool isBlockBadHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block);
friend EffaceableReturn eraseBlockHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block);
friend EffaceableReturn writePageHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block, uint32_t page, const void * buf, uint32_t length);
friend EffaceableReturn readPageHook(effaceable_nand_hal_t * nand, uint32_t bank, uint32_t block, uint32_t page, void * buf, uint32_t length);
friend bool requestPartitionTableDiffHook(effaceable_nand_hal_t * nand, void * buf, uint32_t length);
friend bool providePartitionTableDiffHook(effaceable_nand_hal_t * nand, void * buf, uint32_t length);
protected:
effaceable_nand_hal_t * nand(void);
virtual void setupDeviceContract(void);
private:
void setupNandContract(void);
uint32_t getPageSizeNand(void);
uint32_t getPageCountNand(void);
uint32_t getBlockCountNand(void);
uint32_t getBankCountNand(void);
bool isBlockBadNand(uint32_t bank, uint32_t block);
EffaceableReturn eraseBlockNand(uint32_t bank, uint32_t block);
EffaceableReturn writePageNand(uint32_t bank, uint32_t block, uint32_t page, const void * buf, uint32_t length);
EffaceableReturn readPageNand(uint32_t bank, uint32_t block, uint32_t page, void * buf, uint32_t length);
bool requestPartitionTableDiffNand(void * buf, uint32_t length);
bool providePartitionTableDiffNand(void * buf, uint32_t length);
IOFlashStoragePartition * _partition;
effaceable_nand_hal_t _nand_hal;
};
#endif /* _APPLE_NAND_EFFACEABLE_STORAGE_H */
+158
View File
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2010-11 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
// =============================================================================
#include <IOKit/IOLib.h>
#include "AppleEffaceableNOR.h"
#include "effaceable_contract.h"
#include "effaceable_debug.h"
// =============================================================================
#define debug(...) dlogf((void*)0, __VA_ARGS__ )
// =============================================================================
#ifdef super
#undef super
#endif
#define super AppleEffaceableStorage
OSDefineMetaClassAndStructors(AppleEffaceableNOR, AppleEffaceableStorage);
// =============================================================================
bool
AppleEffaceableNOR::start(IOService *provider)
{
bool ok = false;
debug(INFO, "starting");
setupNorContract();
if (_is_started) {
debug(INFO, "already started");
ok = true;
} else if (0 == (_nor_flash = OSDynamicCast(AppleARMNORFlashDevice, provider))) {
debug(ERR, "bug in kext matching");
} else if (!super::start(provider)) {
debug(ERR, "super failed to start");
} else {
debug(INIT, "started");
_is_started = true;
ok = true;
}
return ok;
}
// =============================================================================
effaceable_nor_hal_t *
AppleEffaceableNOR::nor(void)
{
return &_nor_hal;
}
void
AppleEffaceableNOR::setupDeviceContract(void)
{
startEffaceableNOR(device(), system(), nor(), storage());
}
// =============================================================================
AppleEffaceableNOR * context(effaceable_nor_hal_t * nor)
{
AppleEffaceableNOR * context;
// XXX assert instead?
if (0 == (context = (AppleEffaceableNOR *)nor->opaque))
panic("null context");
return context;
}
uint32_t getRegionCountHook(effaceable_nor_hal_t * nor)
{
return context(nor)->getRegionCountNor();
}
uint32_t getRegionSizeHook(effaceable_nor_hal_t * nor, uint32_t index)
{
return context(nor)->getRegionSizeNor(index);
}
EffaceableReturn eraseRegionHook(effaceable_nor_hal_t * nor, uint32_t index, uint32_t length)
{
return context(nor)->eraseRegionNor(index, length);
}
uint32_t writeRegionHook(effaceable_nor_hal_t * nor, uint32_t index, const void * buf, uint32_t length)
{
return context(nor)->writeRegionNor(index, buf, length);
}
bool readRegionHook(effaceable_nor_hal_t * nor, uint32_t index, void * buf, uint32_t length)
{
return context(nor)->readRegionNor(index, buf, length);
}
// =============================================================================
void
AppleEffaceableNOR::setupNorContract(void)
{
nor()->opaque = this;
nor()->getRegionCount = getRegionCountHook;
nor()->getRegionSize = getRegionSizeHook;
nor()->eraseRegion = eraseRegionHook;
nor()->writeRegion = writeRegionHook;
nor()->readRegion = readRegionHook;
}
uint32_t
AppleEffaceableNOR::getRegionCountNor(void)
{
return _nor_flash->getRegionCount();
}
uint32_t
AppleEffaceableNOR::getRegionSizeNor(uint32_t index)
{
return _nor_flash->getRegionSize(index);
}
EffaceableReturn
AppleEffaceableNOR::eraseRegionNor(uint32_t index, uint32_t length)
{
return efReturn(_nor_flash->eraseRegion(index, 0, length));
}
uint32_t
AppleEffaceableNOR::writeRegionNor(uint32_t index, const void * buf, uint32_t length)
{
return _nor_flash->writeRegion(index, (const UInt8*)buf, length);
}
bool
AppleEffaceableNOR::readRegionNor(uint32_t index, void * buf, uint32_t length)
{
return _nor_flash->readRegion(index, (UInt8*)buf, length);
}
// =============================================================================
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2010-11 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef _APPLE_EFFACEABLE_NOR_H
#define _APPLE_EFFACEABLE_NOR_H
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/platform/AppleARMNORFlashDevice.h>
#include "AppleEffaceableStorage.h"
#include "effaceable_contract.h"
class AppleEffaceableNOR : public AppleEffaceableStorage
{
OSDeclareAbstractStructors(AppleEffaceableNOR);
public:
virtual bool start(IOService * provider);
friend uint32_t getRegionCountHook(effaceable_nor_hal_t * nor);
friend uint32_t getRegionSizeHook(effaceable_nor_hal_t * nor, uint32_t index);
friend EffaceableReturn eraseRegionHook(effaceable_nor_hal_t * nor, uint32_t index, uint32_t length);
friend uint32_t writeRegionHook(effaceable_nor_hal_t * nor, uint32_t index, const void * buf, uint32_t length);
friend bool readRegionHook(effaceable_nor_hal_t * nor, uint32_t index, void * buf, uint32_t length);
protected:
effaceable_nor_hal_t * nor(void);
virtual void setupDeviceContract(void);
private:
void setupNorContract(void);
uint32_t getRegionCountNor(void);
uint32_t getRegionSizeNor(uint32_t index);
EffaceableReturn eraseRegionNor(uint32_t index, uint32_t length);
uint32_t writeRegionNor(uint32_t index, const void * buf, uint32_t length);
bool readRegionNor(uint32_t index, void * buf, uint32_t length);
AppleARMNORFlashDevice * _nor_flash;
bool _is_started;
effaceable_nor_hal_t _nor_hal;
};
#endif /* _APPLE_EFFACEABLE_NOR_H */
@@ -0,0 +1,545 @@
/*
* Copyright (c) 2010-2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <sys/types.h>
#include <sys/random.h>
#include <libkern/zlib.h>
#include <libkern/crypto/sha1.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOUserClient.h>
#include "AppleEffaceableStorageKeys.h"
#include "AppleEffaceableStorageFormat.h"
#include "AppleEffaceableStorage.h"
#include "effaceable_contract.h"
#include "effaceable_debug.h"
// =============================================================================
#define debug(...) dlogf((void*)0, __VA_ARGS__ )
// =============================================================================
#ifdef super
#undef super
#endif
#define super IOService
OSDefineMetaClassAndAbstractStructors(AppleEffaceableStorage, IOService);
// =============================================================================
bool AppleEffaceableStorage::start(IOService *provider)
{
bool ok = false;
debug(INFO, "starting");
if (!super::start(provider)) {
debug(ERR, "super did not start\n");
} else if (NULL == (_work_loop = IOWorkLoop::workLoop())) {
debug(ERR, "couldn't init work loop");
} else if (NULL == (_command_gate = IOCommandGate::commandGate(this))) {
debug(ERR, "couldn't acquire command gate");
} else if ((NULL == (_function_get = OSSymbol::withCString(kAppleEffaceableStorageFunctionGet))) ||
(NULL == (_function_set = OSSymbol::withCString(kAppleEffaceableStorageFunctionSet))) ||
(NULL == (_function_space = OSSymbol::withCString(kAppleEffaceableStorageFunctionSpace))) ||
(NULL == (_function_efface = OSSymbol::withCString(kAppleEffaceableStorageFunctionEfface))) ||
(NULL == (_function_gen_nonce = OSSymbol::withCString(kAppleEffaceableStorageFunctionGenerateNonce)))) {
debug(ERR, "couldn't allocate function symbols");
} else {
// add command gate to work loop
getWorkLoop()->addEventSource(_command_gate);
// commandgate actions
#define _ACTION_CAST(_x) OSMemberFunctionCast(IOCommandGate::Action, this, _x)
_get_action = _ACTION_CAST(&AppleEffaceableStorage::getLockerGated);
_set_action = _ACTION_CAST(&AppleEffaceableStorage::setLockerGated);
_space_action = _ACTION_CAST(&AppleEffaceableStorage::spaceForLockerGated);
_efface_action = _ACTION_CAST(&AppleEffaceableStorage::effaceLockerGated);
_gen_nonce_action = _ACTION_CAST(&AppleEffaceableStorage::generateNonceGated);
_format_action = _ACTION_CAST(&AppleEffaceableStorage::formatStorageGated);
_get_bytes_action = _ACTION_CAST(&AppleEffaceableStorage::getBytesGated);
_wipe_action = _ACTION_CAST(&AppleEffaceableStorage::wipeStorageGated);
#undef _ACTION_CAST
// initalize portable core
setupSystemContract();
setupDeviceContract();
registerService();
ok = true;
}
if (!ok) {
if (NULL != _command_gate) {
_command_gate->release();
_command_gate = NULL;
}
if (NULL != _work_loop) {
_work_loop->release();
_work_loop = NULL;
}
}
return ok;
}
void
AppleEffaceableStorage::registerService(IOOptionBits options)
{
const OSSymbol * user_client;
// hook up the user client
user_client = OSSymbol::withCStringNoCopy("AppleEffaceableStorageUserClient");
setProperty(gIOUserClientClassKey, (OSObject *)user_client);
user_client->release();
super::registerService(options);
}
IOWorkLoop *
AppleEffaceableStorage::getWorkLoop() const
{
return _work_loop;
}
// =============================================================================
IOByteCount
AppleEffaceableStorage::getCapacity(void)
{
return (IOByteCount)storage()->getCapacity(storage());
}
bool
AppleEffaceableStorage::isFormatted(void)
{
return storage()->isFormatted(storage());
}
IOReturn
AppleEffaceableStorage::formatStorage(void)
{
return _command_gate->runAction(_format_action);
}
IOReturn
AppleEffaceableStorage::getBytes(void * client_buf, IOByteCount offset, IOByteCount count)
{
if (PE_i_can_has_debugger(NULL)) {
return _command_gate->runAction(_get_bytes_action, (void *) client_buf, (void *) offset, (void *) count);
} else {
return kIOReturnUnsupported;
}
}
IOReturn
AppleEffaceableStorage::wipeStorage(void)
{
if (PE_i_can_has_debugger(NULL)) {
return _command_gate->runAction(_wipe_action);
} else {
return kIOReturnUnsupported;
}
}
IOReturn
AppleEffaceableStorage::getLocker(UInt32 type_id, void *data, IOByteCount *data_size, bool untrusted)
{
return _command_gate->runAction(_get_action, (void *)type_id, data, (void *)data_size, (void *)untrusted);
}
IOReturn
AppleEffaceableStorage::setLocker(UInt32 type_id, const void *data, IOByteCount data_size, bool untrusted)
{
return _command_gate->runAction(_set_action, (void *)type_id, (void *)data, (void *)data_size, (void *)untrusted);
}
IOReturn
AppleEffaceableStorage::spaceForLocker(UInt32 type_id, IOByteCount *data_space)
{
return _command_gate->runAction(_space_action, (void *)type_id, (void *)data_space);
}
IOReturn
AppleEffaceableStorage::effaceLocker(UInt32 type_id, bool untrusted)
{
return _command_gate->runAction(_efface_action, (void *)type_id, (void *)untrusted);
}
IOReturn
AppleEffaceableStorage::generateNonce(void * hash)
{
return _command_gate->runAction(_gen_nonce_action, hash);
}
IOReturn
AppleEffaceableStorage::callPlatformFunction(
const OSSymbol *functionSymbol,
bool waitForFunction,
void *param1,
void *param2,
void *param3,
void *param4)
{
if (functionSymbol == _function_get)
return getLocker((UInt32)(uintptr_t)param1, param2, (IOByteCount *)param3, (bool)param4);
if (functionSymbol == _function_set)
return setLocker((UInt32)(uintptr_t)param1, param2, (IOByteCount)param3, (bool)param4);
if (functionSymbol == _function_space)
return effaceLocker((UInt32)(uintptr_t)param1, (IOByteCount *)param2);
if (functionSymbol == _function_efface)
return effaceLocker((UInt32)(uintptr_t)param1, (bool)param2);
if (functionSymbol == _function_gen_nonce)
return generateNonce(param1);
return(IOService::callPlatformFunction(functionSymbol, waitForFunction, param1, param2, param3, param4));
}
// =============================================================================
IOReturn
AppleEffaceableStorage::formatStorageGated(void)
{
return ioReturn(storage()->formatStorage(storage()));
}
IOReturn
AppleEffaceableStorage::getBytesGated(void * client_buf, IOByteCount offset, IOByteCount count)
{
return ioReturn(storage()->getBytes(storage(), client_buf, offset, count));
}
IOReturn
AppleEffaceableStorage::wipeStorageGated(void * tmp_buf)
{
return ioReturn(storage()->wipeStorage(storage(), tmp_buf));
}
// =============================================================================
IOReturn
AppleEffaceableStorage::getLockerGated(UInt32 type_id, void *data, IOByteCount *data_size, bool untrusted)
{
return ioReturn(storage()->getLocker(storage(), type_id, data, (uint32_t *)data_size, untrusted));
}
IOReturn
AppleEffaceableStorage::setLockerGated(UInt32 type_id, const void *data, IOByteCount data_size, bool untrusted)
{
return ioReturn(storage()->setLocker(storage(), type_id, data, (uint32_t)data_size, untrusted));
}
IOReturn
AppleEffaceableStorage::spaceForLockerGated(UInt32 type_id, IOByteCount *data_space)
{
return ioReturn(storage()->spaceForLocker(storage(), type_id, (uint32_t *)data_space));
}
IOReturn
AppleEffaceableStorage::effaceLockerGated(UInt32 type_id, bool untrusted)
{
return ioReturn(storage()->effaceLocker(storage(), type_id, untrusted));
}
IOReturn
AppleEffaceableStorage::generateNonceGated(void * hash)
{
return ioReturn(storage()->generateNonce(storage(), hash));
}
// =============================================================================
effaceable_storage_t *
AppleEffaceableStorage::storage(void)
{
return &_storage;
}
effaceable_device_t *
AppleEffaceableStorage::device(void)
{
return &_device;
}
effaceable_system_t *
AppleEffaceableStorage::system(void)
{
return &_system;
}
EffaceableReturn
AppleEffaceableStorage::efReturn(IOReturn ret)
{
EffaceableReturn cast = kEffaceableReturnInvalid;
switch (ret) {
case kIOReturnSuccess : cast = kEffaceableReturnSuccess ; break;
case kIOReturnError : cast = kEffaceableReturnError ; break;
case kIOReturnNotFound : cast = kEffaceableReturnNotFound ; break;
case kIOReturnUnsupported : cast = kEffaceableReturnUnsupported ; break;
case kIOReturnNotPrivileged : cast = kEffaceableReturnNotPrivileged ; break;
case kIOReturnNotPermitted : cast = kEffaceableReturnNotPermitted ; break;
case kIOReturnBadArgument : cast = kEffaceableReturnBadArgument ; break;
case kIOReturnBadMedia : cast = kEffaceableReturnBadMedia ; break;
case kIOReturnIOError : cast = kEffaceableReturnIOError ; break;
case kIOReturnNoMemory : cast = kEffaceableReturnNoMemory ; break;
case kIOReturnNoSpace : cast = kEffaceableReturnNoSpace ; break;
case kIOReturnInternalError : cast = kEffaceableReturnInternalError ; break;
case kIOReturnUnformattedMedia : cast = kEffaceableReturnUnformattedMedia; break;
}
return cast;
}
IOReturn
AppleEffaceableStorage::ioReturn(EffaceableReturn ret)
{
IOReturn cast = kIOReturnInvalid;
switch (ret) {
case kEffaceableReturnSuccess : cast = kIOReturnSuccess ; break;
case kEffaceableReturnError : cast = kIOReturnError ; break;
case kEffaceableReturnNotFound : cast = kIOReturnNotFound ; break;
case kEffaceableReturnUnsupported : cast = kIOReturnUnsupported ; break;
case kEffaceableReturnNotPrivileged : cast = kIOReturnNotPrivileged ; break;
case kEffaceableReturnNotPermitted : cast = kIOReturnNotPermitted ; break;
case kEffaceableReturnBadArgument : cast = kIOReturnBadArgument ; break;
case kEffaceableReturnBadMedia : cast = kIOReturnBadMedia ; break;
case kEffaceableReturnIOError : cast = kIOReturnIOError ; break;
case kEffaceableReturnNoMemory : cast = kIOReturnNoMemory ; break;
case kEffaceableReturnNoSpace : cast = kIOReturnNoSpace ; break;
case kEffaceableReturnInternalError : cast = kIOReturnInternalError ; break;
case kEffaceableReturnUnformattedMedia : cast = kIOReturnUnformattedMedia; break;
}
return cast;
}
// =============================================================================
int
AppleEffaceableStorage::logf(void * ignored, const char * fmt, ...)
{
int err;
va_list ap;
va_start(ap, fmt);
err = vlogfSys(fmt, ap);
va_end(ap);
return err;
}
// =============================================================================
void
AppleEffaceableStorage::handleBootArgs(void)
{
uint32_t arg_flag = 0;
bool enable_wipe = false;
bool enable_full_scan = false;
// boot-arg support to enable/disable of media wipe
if (PE_parse_boot_argn("effaceable-enable-wipe", &arg_flag, sizeof (arg_flag)) && arg_flag) {
enable_wipe = (0 != arg_flag);
// XXX plumb down through to core implementation
debug(INIT, "wipe %sabled via boot-arg", enable_wipe ? "en" : "dis");
}
// boot-arg support to enable/disable full scan
if (PE_parse_boot_argn("effaceable-enable-full-scan", &arg_flag, sizeof (arg_flag)) && arg_flag) {
enable_full_scan = (0 != arg_flag);
// XXX plumb down through to core implementation
debug(INIT, "full scan %sabled via boot-arg", enable_full_scan ? "en" : "dis");
}
}
// =============================================================================
AppleEffaceableStorage * context(effaceable_system_t * system)
{
AppleEffaceableStorage * context;
// XXX assert instead?
if (NULL == (context = (AppleEffaceableStorage *)system->opaque))
panic("null context");
return context;
}
void * allocMemHook(effaceable_system_t * system, uint32_t size)
{
return context(system)->allocMemSys(size);
}
void freeMemHook(effaceable_system_t * system, void * buf, uint32_t size)
{
context(system)->freeMemSys(buf, size);
}
void * setMemHook(effaceable_system_t * system, void * buf, uint8_t val, uint32_t size)
{
return context(system)->setMemSys(buf, val, size);
}
void * moveMemHook(effaceable_system_t * system, void * dst, const void * src, uint32_t size)
{
return context(system)->moveMemSys(dst, src, size);
}
int cmpMemHook(effaceable_system_t * system, const void * lhs, const void * rhs, uint32_t size)
{
return context(system)->cmpMemSys(lhs, rhs, size);
}
void readRandomHook(effaceable_system_t * system, void * buf, uint32_t size)
{
context(system)->readRandomSys(buf, size);
}
void calcSHA1Hook(effaceable_system_t * system, const void * buf, uint32_t size, void * hash)
{
return context(system)->calcSHA1Sys(buf, size, hash);
}
uint32_t crc32Hook(effaceable_system_t * system, uint32_t crc, const void * buf, uint32_t size, bool ignored)
{
return context(system)->crc32Sys(crc, buf, size);
}
bool setPropertyHook(effaceable_system_t * system, const char * key, uint32_t value)
{
return context(system)->setPropertySys(key, value);
}
void panicHook(effaceable_system_t * system, const char * msg)
{
context(system)->panicSys(msg);
}
int vlogfHook(effaceable_system_t * system, const char * fmt, va_list ap)
{
return context(system)->vlogfSys(fmt, ap);
}
// =============================================================================
void
AppleEffaceableStorage::setupSystemContract(void)
{
// XXX convert to appropriate type of AssertMacros
if (sizeof(uint32_t) != sizeof(IOByteCount))
panic("(sizeof(uint32_t) != sizeof(IOByteCount))");
system()->opaque = this;
system()->allocMem = allocMemHook;
system()->freeMem = freeMemHook;
system()->setMem = setMemHook;
system()->moveMem = moveMemHook;
system()->cmpMem = cmpMemHook;
system()->readRandom = readRandomHook;
system()->calcSHA1 = calcSHA1Hook;
system()->crc32 = crc32Hook;
system()->setProperty = setPropertyHook;
system()->panicSys = panicHook;
system()->vlogf = vlogfHook;
}
void *
AppleEffaceableStorage::allocMemSys(uint32_t size)
{
void * buf = IOMalloc(size);
if (0 == buf) {
panic("no memory");
}
return buf;
}
void
AppleEffaceableStorage::freeMemSys(void * buf, uint32_t size)
{
IOFree(buf, size);
}
void *
AppleEffaceableStorage::setMemSys(void * buf, uint8_t val, uint32_t size)
{
return memset(buf, val, size);
}
void *
AppleEffaceableStorage::moveMemSys(void * dst, const void * src, uint32_t size)
{
return memmove(dst, src, size);
}
int
AppleEffaceableStorage::cmpMemSys(const void * lhs, const void * rhs, uint32_t size)
{
return memcmp(lhs, rhs, size);
}
void
AppleEffaceableStorage::readRandomSys(void * buf, uint32_t size)
{
read_random(buf, size);
}
void
AppleEffaceableStorage::calcSHA1Sys(const void * buf, uint32_t size, void * hash)
{
SHA1_CTX ctx;
SHA1Init(&ctx);
SHA1Update(&ctx, buf, size);
SHA1Final(hash, &ctx);
}
uint32_t
AppleEffaceableStorage::crc32Sys(uint32_t crc, const void * buf, uint32_t size)
{
return crc32(crc, buf, size);
}
bool
AppleEffaceableStorage::setPropertySys(const char * key, uint32_t value)
{
return setProperty(key, value, 32);
}
void
AppleEffaceableStorage::panicSys(const char * msg)
{
panic(msg);
}
int
AppleEffaceableStorage::vlogfSys(const char * fmt, va_list ap)
{
IOLogv(fmt, ap);
// XXX Given that IOLogv doesn't return character printed count,
// as least common denominator, it's probably best to reduce vlogf
// contract to void return value.
return 0;
}
// =============================================================================
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2010-11 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef _APPLE_EFFACEABLE_STORAGE_H
#define _APPLE_EFFACEABLE_STORAGE_H
// =============================================================================
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOCommandGate.h>
#include "AppleEffaceableStorageKeys.h"
#include "effaceable_contract.h"
// =============================================================================
class AppleEffaceableStorage : public IOService
{
OSDeclareAbstractStructors(AppleEffaceableStorage);
public:
/* client API */
IOReturn getLocker(UInt32 type_id, void *data, IOByteCount *data_size, bool untrusted = false);
IOReturn setLocker(UInt32 type_id, const void *data, IOByteCount data_size, bool untrusted = false);
IOReturn spaceForLocker(UInt32 type_id, IOByteCount *data_space);
IOReturn effaceLocker(UInt32 type_id, bool untrusted = false);
IOReturn generateNonce(void * hash);
/* additional public functions intended for manufacturing and/or diagnostics only */
IOReturn getBytes(void * client_buf, IOByteCount offset, IOByteCount count);
IOReturn wipeStorage(void);
IOByteCount getCapacity(void);
bool isFormatted(void);
IOReturn formatStorage(void);
protected:
/* subclass SPI */
effaceable_storage_t * storage(void);
effaceable_device_t * device(void);
effaceable_system_t * system(void);
EffaceableReturn efReturn(IOReturn ret);
IOReturn ioReturn(EffaceableReturn ret);
int logf(void * ignored, const char * fmt, ...);
virtual void setupDeviceContract(void) = 0;
public:
/* IOKit hooks */
virtual bool start(IOService * provider);
virtual void registerService(IOOptionBits options = 0);
virtual IOWorkLoop * getWorkLoop() const;
virtual IOReturn callPlatformFunction(const OSSymbol *functionSymbol, bool waitForFunction,
void *param1, void *param2, void *param3, void *param4);
private:
/* gated versions of public methods */
IOReturn wipeStorageGated(void * tmp_buf);
IOReturn formatStorageGated(void);
IOReturn getBytesGated(void * client_buf, IOByteCount offset, IOByteCount count);
IOReturn getLockerGated(UInt32 type_id, void *data, IOByteCount *data_size, bool untrusted);
IOReturn setLockerGated(UInt32 type_id, const void *data, IOByteCount data_size, bool untrusted);
IOReturn spaceForLockerGated(UInt32 type_id, IOByteCount *data_spage);
IOReturn effaceLockerGated(UInt32 type_id, bool untrusted);
IOReturn generateNonceGated(void * hash);
/* methods to help get portable core setup and configured */
void setupSystemContract(void);
void handleBootArgs(void);
/* implementation of portable core system services contract */
void * allocMemSys(uint32_t size);
void freeMemSys(void * buf, uint32_t size);
void * setMemSys(void * buf, uint8_t val, uint32_t size);
void * moveMemSys(void * dst, const void * src, uint32_t size);
int cmpMemSys(const void * lhs, const void * rhs, uint32_t size);
void readRandomSys(void * buf, uint32_t size);
void calcSHA1Sys(const void * buf, uint32_t size, void * hash);
uint32_t crc32Sys(uint32_t crc, const void * buf, uint32_t size);
bool setPropertySys(const char * key, uint32_t value);
void panicSys(const char * msg);
int vlogfSys(const char * fmt, va_list ap);
private:
/* friend C function hooks implementing trampoline back to C++ for portable core system contract */
friend void * allocMemHook(effaceable_system_t * system, uint32_t size);
friend void freeMemHook(effaceable_system_t * system, void * buf, uint32_t size);
friend void * setMemHook(effaceable_system_t * system, void * buf, uint8_t val, uint32_t size);
friend void * moveMemHook(effaceable_system_t * system, void * dst, const void * src, uint32_t size);
friend int cmpMemHook(effaceable_system_t * system, const void * lhs, const void * rhs, uint32_t size);
friend void readRandomHook(effaceable_system_t * system, void * buf, uint32_t size);
friend void calcSHA1Hook(effaceable_system_t * system, const void * buf, uint32_t size, void * hash);
friend uint32_t crc32Hook(effaceable_system_t * system, uint32_t crc, const void * buf, uint32_t size, bool ignored);
friend bool setPropertyHook(effaceable_system_t * system, const char * key, uint32_t value);
friend void panicHook(effaceable_system_t * system, const char * msg);
friend int vlogfHook(effaceable_system_t * system, const char * fmt, va_list ap);
private:
/* implementation data */
IOCommandGate * _command_gate;
IOWorkLoop * _work_loop;
const OSSymbol * _function_get;
const OSSymbol * _function_set;
const OSSymbol * _function_space;
const OSSymbol * _function_efface;
const OSSymbol * _function_gen_nonce;
IOCommandGate::Action _get_action;
IOCommandGate::Action _set_action;
IOCommandGate::Action _space_action;
IOCommandGate::Action _efface_action;
IOCommandGate::Action _gen_nonce_action;
IOCommandGate::Action _format_action;
IOCommandGate::Action _wipe_action;
IOCommandGate::Action _get_bytes_action;
effaceable_storage_t _storage;
effaceable_system_t _system;
effaceable_device_t _device;
};
// =============================================================================
#endif /* _APPLE_EFFACEABLE_STORAGE_H */
@@ -0,0 +1,301 @@
/*
* Copyright (c) 2010-2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
// =============================================================================
#include <IOKit/IOTypes.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOUserClient.h>
#include "AppleEffaceableStorage.h"
#include "AppleEffaceableStorageKeys.h"
#include "AppleEffaceableStorageUserClient.h"
// =============================================================================
// XXX correct hard-coding of SHA1 buffer size
#define SHA1_HASH_SIZE 20
// =============================================================================
#define APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INIT (1<<0)
#define APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_ERR (1<<1)
#define APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_WARN (1<<2)
#define APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INFO (1<<3)
#define APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_SPEW (1<<4)
#define APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_INIT "INIT"
#define APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_ERR "ERROR"
#define APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_WARN "WARNING"
#define APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_INFO "INFO"
#define APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_SPEW "SPEW"
#define APPLE_EFFACEABLE_USER_CLIENT_DEBUG_ALL (APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INIT | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_ERR | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_WARN | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INFO | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_SPEW)
#define APPLE_EFFACEABLE_USER_CLIENT_DEBUG_MOST (APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INIT | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_ERR | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_WARN | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INFO)
#define APPLE_EFFACEABLE_USER_CLIENT_DEBUG_DEFAULT (APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_INIT | \
APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_ERR)
#ifdef DEBUG_BUILD
# define APPLE_EFFACEABLE_USER_CLIENT_DEBUG APPLE_EFFACEABLE_USER_CLIENT_DEBUG_MOST
#else
# define APPLE_EFFACEABLE_USER_CLIENT_DEBUG APPLE_EFFACEABLE_USER_CLIENT_DEBUG_DEFAULT
#endif
#if defined(APPLE_EFFACEABLE_USER_CLIENT_DEBUG) && APPLE_EFFACEABLE_USER_CLIENT_DEBUG
# define debug(fac, fmt, args...) \
do { \
if (APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_##fac & \
APPLE_EFFACEABLE_USER_CLIENT_DEBUG) { \
kprintf("AppleEffaceableStorageUserClient::%s():[%s] " fmt "\n", \
__FUNCTION__, \
APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_##fac , \
##args ); \
} \
} while(0)
# define hexdump(fac, bytes, count) \
do { \
if (APPLE_EFFACEABLE_USER_CLIENT_DBGMSK_##fac & \
APPLE_EFFACEABLE_USER_CLIENT_DEBUG) { \
uint32_t i, j; \
for (i = 0; i < count; i += 16) { \
kprintf("AppleEffaceableStorageUserClient::%s():[%s] 0x%08x:", \
__FUNCTION__, \
APPLE_EFFACEABLE_USER_CLIENT_DBGTAG_##fac , \
((uint32_t) bytes) + i); \
for (j = 0; (j < 16) && ((i + j) < count); j++) \
kprintf(" %2.2x", ((uint8_t*)bytes)[i+j]); \
kprintf("\n"); \
} \
} \
} while(0)
#else
# define debug(fac, fmt, args...) do { /* nothing */ } while(0)
# define hexdump(fac, bytes, count) do { /* nothing */ } while(0)
#endif
// =============================================================================
#ifdef super
#undef super
#endif
#define super IOUserClient
OSDefineMetaClassAndStructors(AppleEffaceableStorageUserClient, IOUserClient);
// =============================================================================
bool
AppleEffaceableStorageUserClient::start(IOService *provider)
{
bool ok = false;
_provider = OSDynamicCast(AppleEffaceableStorage, provider);
if (NULL == _provider) {
debug(ERR, "bug in kext matching");
} else if (!super::start(provider)) {
debug(ERR, "super failed to start");
} else {
debug(INFO, "started");
ok = true;
}
return ok;
}
IOReturn
AppleEffaceableStorageUserClient::clientClose(void)
{
terminate();
return kIOReturnSuccess;
}
IOReturn
AppleEffaceableStorageUserClient::externalMethod(uint32_t selector,
IOExternalMethodArguments * arguments,
IOExternalMethodDispatch *dispatch,
OSObject *target,
void *reference)
{
IOReturn ok = kIOReturnSuccess;
bool secure_root;
// require administrator privilege
if (kIOReturnSuccess != clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator)) {
debug(ERR, "not authorized");
return kIOReturnNotPrivileged;
}
#ifdef DEBUG_BUILD
secure_root = true;
#else
// some operations require a secure root
if (kIOReturnSuccess != (ok = _provider->getProvider()->callPlatformFunction("SecureRoot",
false,
_provider->getProvider(),
&secure_root,
0, 0))) {
debug(ERR, "failed to determine root trust state");
secure_root = false;
}
#endif // DEBUG_BUILD
switch (selector) {
case kAppleEffaceableStorageMethodGetCapacity:
if (arguments->scalarOutputCount != 1) {
debug(ERR, "getCapacity: missing output argument");
ok = kIOReturnBadArgument;
} else {
arguments->scalarOutput[0] = _provider->getCapacity();
}
break;
case kAppleEffaceableStorageMethodIsFormatted:
if (arguments->scalarOutputCount != 1) {
debug(ERR, "isFormatted: missing output argument");
ok = kIOReturnBadArgument;
} else {
arguments->scalarOutput[0] = _provider->isFormatted();
}
break;
case kAppleEffaceableStorageMethodFormatStorage:
if (!secure_root) {
debug(ERR, "format attempt from untrusted root");
} else {
ok = _provider->formatStorage();
}
break;
case kAppleEffaceableStorageMethodWipeStorage:
if (!secure_root) {
debug(ERR, "wipe attempt from untrusted root");
} else {
ok = _provider->wipeStorage();
}
break;
case kAppleEffaceableStorageMethodGetLocker:
if ((arguments->scalarInputCount != 1) ||
(arguments->scalarOutputCount != 1)) {
debug(ERR, "getLocker: missing input/output arguments");
ok = kIOReturnBadArgument;
} else {
IOByteCount data_size = arguments->structureOutputSize;
ok = _provider->getLocker(arguments->scalarInput[0],
arguments->structureOutput,
&data_size,
!secure_root);
arguments->scalarOutput[0] = data_size;
// if we didn't clip the data, report the actual output size
if (data_size < arguments->structureOutputSize)
arguments->structureOutputSize = data_size;
}
break;
case kAppleEffaceableStorageMethodSetLocker:
if ((arguments->scalarInputCount != 1) ||
(arguments->structureInputSize < 1)) {
debug(ERR, "setLocker: missing input arguments");
ok = kIOReturnBadArgument;
} else {
ok = _provider->setLocker(arguments->scalarInput[0],
arguments->structureInput,
arguments->structureInputSize,
!secure_root);
}
break;
case kAppleEffaceableStorageMethodSpace:
if ((arguments->scalarInputCount != 1) ||
(arguments->scalarOutputCount != 1)) {
debug(ERR, "lockerSpace: missing input/output arguments");
ok = kIOReturnBadArgument;
} else {
IOByteCount data_space;
ok = _provider->spaceForLocker(arguments->scalarInput[0],
&data_space);
arguments->scalarOutput[0] = data_space;
}
break;
case kAppleEffaceableStorageMethodEffaceLocker:
if (arguments->scalarInputCount != 1) {
debug(ERR, "effaceLocker: missing input argument");
ok = kIOReturnBadArgument;
} else if (!secure_root && arguments->scalarInput[0] == kAppleEffaceableStorageLockerWildcard) {
debug(ERR, "effaceLocker: untrusted attempt to efface by wildcard");
ok = kIOReturnNotPermitted;
} else {
ok = _provider->effaceLocker(arguments->scalarInput[0], !secure_root);
}
break;
case kAppleEffaceableStorageMethodGenerateNonce:
if (arguments->structureOutputSize != SHA1_HASH_SIZE) {
debug(ERR, "generateNonce: missing output argument");
ok = kIOReturnBadArgument;
} else {
ok = _provider->generateNonce(arguments->structureOutput);
if (kIOReturnSuccess != ok) {
arguments->structureOutputSize = 0;
}
}
break;
//
// Methods below are not for production use and may only be used when kernel debug enabled via boot-args.
//
case kAppleEffaceableStorageMethodGetBytes:
if ((arguments->scalarInputCount != 1) ||
(arguments->structureOutputSize < 1)) {
ok = kIOReturnBadArgument;
} else if (!PE_i_can_has_debugger(NULL)) {
debug(ERR, "getBytes is only allowed when kernel debug is enabled");
ok = kIOReturnUnsupported;
} else {
ok = _provider->getBytes(arguments->structureOutput, arguments->scalarInput[0], arguments->structureOutputSize);
if (kIOReturnSuccess != ok) {
debug(ERR, "getBytes from user client to service failed");
} else {
debug(SPEW, "read %u bytes from offset %llu", arguments->structureOutputSize, arguments->scalarInput[0]);
}
}
break;
default:
debug(ERR, "bad selector %u", selector);
ok = kIOReturnUnsupported;
break;
}
return ok;
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2010-11 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef _APPLE_EFFACEABLE_USER_CLIENT_H
#define _APPLE_EFFACEABLE_USER_CLIENT_H
#include <IOKit/IOUserClient.h>
#include "AppleEffaceableStorage.h"
class AppleEffaceableStorageUserClient : public IOUserClient
{
OSDeclareAbstractStructors(AppleEffaceableStorageUserClient);
public:
virtual bool start(IOService * provider);
virtual IOReturn clientClose(void);
virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments * arguments,
IOExternalMethodDispatch * dispatch, OSObject * target,
void * reference);
private:
AppleEffaceableStorage * _provider;
};
#endif /* _APPLE_EFFACEABLE_USER_CLIENT_H */
+77
View File
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.apple.driver.AppleEffaceableStorage</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>OSBundleCompatibleVersion</key>
<string>1.0</string>
<key>IOKitPersonalities</key>
<dict>
<key>AppleEffaceableNAND</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.apple.driver.AppleEffaceableStorage</string>
<key>IOClass</key>
<string>AppleEffaceableNAND</string>
<key>IOPropertyMatch</key>
<array>
<dict>
<key>Content Hint</key>
<string>Effaceable</string>
</dict>
</array>
<key>IOProviderClass</key>
<string>IOFlashMedia</string>
</dict>
<key>AppleEffaceableNOR</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.apple.driver.AppleEffaceableStorage</string>
<key>IOClass</key>
<string>AppleEffaceableNOR</string>
<key>IONameMatch</key>
<string>effaceable,nor</string>
<key>IOProviderClass</key>
<string>AppleARMNORFlashDevice</string>
</dict>
</dict>
<key>OSBundleCompatibleVersion</key>
<string>1.0.0</string>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.driver.AppleARMPlatform</key>
<string>1.0.0</string>
<key>com.apple.iokit.IOFlashStorage</key>
<string>1.0.0</string>
<key>com.apple.kpi.bsd</key>
<string>8.0</string>
<key>com.apple.kpi.iokit</key>
<string>8.0</string>
<key>com.apple.kpi.libkern</key>
<string>8.0</string>
<key>com.apple.kpi.mach</key>
<string>8.0</string>
<key>com.apple.kpi.unsupported</key>
<string>8.0</string>
</dict>
</dict>
</plist>