X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..9bccf70c0258c7cac2dcb80011b2a964d884c552:/iokit/Kernel/IONVRAM.cpp diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index e4bc666b2..738a03cfa 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -42,7 +42,13 @@ bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) _nvramImage = IONew(UInt8, kIODTNVRAMImageSize); if (_nvramImage == 0) return false; - + + _nvramPartitionOffsets = OSDictionary::withCapacity(1); + if (_nvramPartitionOffsets == 0) return false; + + _nvramPartitionLengths = OSDictionary::withCapacity(1); + if (_nvramPartitionLengths == 0) return false; + _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci"); if (_registryPropertiesKey == 0) return false; @@ -51,7 +57,11 @@ bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) { - UInt32 currentOffset = 0; + char partitionID[18]; + UInt32 partitionOffset, partitionLength; + UInt32 freePartitionOffset, freePartitionSize; + UInt32 currentLength, currentOffset = 0; + OSNumber *partitionOffsetNumber, *partitionLengthNumber; if (_nvramController != 0) return; @@ -59,26 +69,58 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); - // Find the offsets for the OF, XPRAM and NameRegistry partitions in NVRAM. + // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions. _ofPartitionOffset = 0xFFFFFFFF; _xpramPartitionOffset = 0xFFFFFFFF; _nrPartitionOffset = 0xFFFFFFFF; + _piPartitionOffset = 0xFFFFFFFF; + freePartitionOffset = 0xFFFFFFFF; + freePartitionSize = 0; if (getPlatform()->getBootROMType()) { // Look through the partitions to find the OF, MacOS partitions. while (currentOffset < kIODTNVRAMImageSize) { - if (strcmp((const char *)_nvramImage + currentOffset + 4, "common") == 0) { - _ofPartitionOffset = currentOffset + 16; - _ofPartitionSize = - (((UInt16 *)(_nvramImage + currentOffset))[1] - 1) * 0x10; - } else if (strcmp((const char *)_nvramImage + currentOffset + 4, "APL,MacOS75") == 0) { - _xpramPartitionOffset = currentOffset + 16; + currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16; + + partitionOffset = currentOffset + 16; + partitionLength = currentLength - 16; + + if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMOFPartitionName, 12) == 0) { + _ofPartitionOffset = partitionOffset; + _ofPartitionSize = partitionLength; + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMXPRAMPartitionName, 12) == 0) { + _xpramPartitionOffset = partitionOffset; _xpramPartitionSize = kIODTNVRAMXPRAMSize; _nrPartitionOffset = _xpramPartitionOffset + _xpramPartitionSize; - _nrPartitionSize = - (((UInt16 *)(_nvramImage + currentOffset))[1] - 1) * 0x10 - - _xpramPartitionSize; + _nrPartitionSize = partitionLength - _xpramPartitionSize; + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMPanicInfoPartitonName, 12) == 0) { + _piPartitionOffset = partitionOffset; + _piPartitionSize = partitionLength; + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMFreePartitionName, 12) == 0) { + freePartitionOffset = currentOffset; + freePartitionSize = currentLength; + } else { + // Construct the partition ID from the signature and name. + sprintf(partitionID, "0x%02x,", + *(UInt8 *)(_nvramImage + currentOffset)); + strncpy(partitionID + 5, + (const char *)(_nvramImage + currentOffset + 4), 12); + partitionID[17] = '\0'; + + partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32); + partitionLengthNumber = OSNumber::withNumber(partitionLength, 32); + + // Save the partition offset and length + _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber); + _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber); + + partitionOffsetNumber->release(); + partitionLengthNumber->release(); } - currentOffset += ((short *)(_nvramImage + currentOffset))[1] * 16; + currentOffset += currentLength; } } else { // Use the fixed address for old world machines. @@ -97,6 +139,60 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) if (_nrPartitionOffset != 0xFFFFFFFF) _nrImage = _nvramImage + _nrPartitionOffset; + if (_piPartitionOffset == 0xFFFFFFFF) { + if (freePartitionSize > 0x20) { + // Set the signature to 0xa1. + _nvramImage[freePartitionOffset] = 0xa1; + // Set the checksum to 0. + _nvramImage[freePartitionOffset + 1] = 0; + // Set the name for the Panic Info partition. + strncpy((char *)(_nvramImage + freePartitionOffset + 4), + kIODTNVRAMPanicInfoPartitonName, 12); + + // Calculate the partition offset and size. + _piPartitionOffset = freePartitionOffset + 0x10; + _piPartitionSize = 0x800; + if (_piPartitionSize + 0x20 > freePartitionSize) + _piPartitionSize = freePartitionSize - 0x20; + + _piImage = _nvramImage + _piPartitionOffset; + + // Zero the new partition. + bzero(_piImage, _piPartitionSize); + + // Set the partition size. + *(UInt16 *)(_nvramImage + freePartitionOffset + 2) = + (_piPartitionSize / 0x10) + 1; + + // Set the partition checksum. + _nvramImage[freePartitionOffset + 1] = + calculatePartitionChecksum(_nvramImage + freePartitionOffset); + + // Calculate the free partition offset and size. + freePartitionOffset += _piPartitionSize + 0x10; + freePartitionSize -= _piPartitionSize + 0x10; + + // Set the signature to 0x7f. + _nvramImage[freePartitionOffset] = 0x7f; + // Set the checksum to 0. + _nvramImage[freePartitionOffset + 1] = 0; + // Set the name for the free partition. + strncpy((char *)(_nvramImage + freePartitionOffset + 4), + kIODTNVRAMFreePartitionName, 12); + // Set the partition size. + *(UInt16 *)(_nvramImage + freePartitionOffset + 2) = + freePartitionSize / 0x10; + // Set the partition checksum. + _nvramImage[freePartitionOffset + 1] = + calculatePartitionChecksum(_nvramImage + freePartitionOffset); + + // Set the nvram image as dirty. + _nvramImageDirty = true; + } + } else { + _piImage = _nvramImage + _piPartitionOffset; + } + initOFVariables(); } @@ -104,7 +200,8 @@ void IODTNVRAM::sync(void) { if (!_nvramImageDirty && !_ofImageDirty) return; - syncOFVariables(); + // Don't try to sync OF Variables if the system has already paniced. + if (!_systemPaniced) syncOFVariables(); _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); _nvramController->sync(); @@ -205,6 +302,9 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) if (_ofDict->getObject(aKey) == 0) return false; } + // Don't allow change of 'aapl,panic-info'. + if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return false; + // Make sure the object is of the correct type. propType = getOFVariableType(aKey); switch (propType) { @@ -280,8 +380,7 @@ IOReturn IODTNVRAM::setProperties(OSObject *properties) IOReturn IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer, IOByteCount length) { - if ((_nvramImage == 0) || (_xpramPartitionOffset == 0)) - return kIOReturnNotReady; + if (_xpramImage == 0) return kIOReturnUnsupported; if ((buffer == 0) || (length <= 0) || (offset < 0) || (offset + length > kIODTNVRAMXPRAMSize)) @@ -295,8 +394,7 @@ IOReturn IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer, IOReturn IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer, IOByteCount length) { - if ((_nvramImage == 0) || (_xpramPartitionOffset == 0)) - return kIOReturnNotReady; + if (_xpramImage == 0) return kIOReturnUnsupported; if ((buffer == 0) || (length <= 0) || (offset < 0) || (offset + length > kIODTNVRAMXPRAMSize)) @@ -337,9 +435,101 @@ IOReturn IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry, return err; } +OSDictionary *IODTNVRAM::getNVRAMPartitions(void) +{ + return _nvramPartitionLengths; +} +IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, + IOByteCount offset, UInt8 *buffer, + IOByteCount length) +{ + OSNumber *partitionOffsetNumber, *partitionLengthNumber; + UInt32 partitionOffset, partitionLength; + + partitionOffsetNumber = + (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); + partitionLengthNumber = + (OSNumber *)_nvramPartitionLengths->getObject(partitionID); + + if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) + return kIOReturnNotFound; + + partitionOffset = partitionOffsetNumber->unsigned32BitValue(); + partitionLength = partitionLengthNumber->unsigned32BitValue(); + + if ((buffer == 0) || (length <= 0) || (offset < 0) || + (offset + length > partitionLength)) + return kIOReturnBadArgument; + + bcopy(_nvramImage + partitionOffset + offset, buffer, length); + + return kIOReturnSuccess; +} -// Private methods for Open Firmware variable access. +IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, + IOByteCount offset, UInt8 *buffer, + IOByteCount length) +{ + OSNumber *partitionOffsetNumber, *partitionLengthNumber; + UInt32 partitionOffset, partitionLength; + + partitionOffsetNumber = + (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); + partitionLengthNumber = + (OSNumber *)_nvramPartitionLengths->getObject(partitionID); + + if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) + return kIOReturnNotFound; + + partitionOffset = partitionOffsetNumber->unsigned32BitValue(); + partitionLength = partitionLengthNumber->unsigned32BitValue(); + + if ((buffer == 0) || (length <= 0) || (offset < 0) || + (offset + length > partitionLength)) + return kIOReturnBadArgument; + + bcopy(buffer, _nvramImage + partitionOffset + offset, length); + + _nvramImageDirty = true; + + return kIOReturnSuccess; +} + +UInt32 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + if ((_piImage == 0) || (length <= 0)) return 0; + + if (length > (_piPartitionSize - 4)) + length = _piPartitionSize - 4; + + // Save the Panic Info. + bcopy(buffer, _piImage + 4, length); + + // Save the Panic Info length. + *(UInt32 *)_piImage = length; + + _nvramImageDirty = true; + + _systemPaniced = true; + + return length; +} + +// Private methods + +UInt8 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader) +{ + UInt8 cnt, isum, csum = 0; + + for (cnt = 0; cnt < 0x10; cnt++) { + isum = csum + partitionHeader[cnt]; + if (isum < csum) isum++; + csum = isum; + } + + return csum; +} struct OWVariablesHeader { UInt16 owMagic; @@ -416,6 +606,20 @@ IOReturn IODTNVRAM::initOFVariables(void) propObject->release(); } } + + // Create the 'aapl,panic-info' property if needed. + if (_piImage != 0) { + propDataLength = *(UInt32 *)_piImage; + if ((propDataLength != 0) && (propDataLength < (_piPartitionSize - 4))) { + propObject = OSData::withBytes(_piImage + 4, propDataLength); + _ofDict->setObject(kIODTNVRAMPanicInfoKey, propObject); + propObject->release(); + + // Clear the length from _piImage and mark dirty. + *(UInt32 *)_piImage = 0; + _nvramImageDirty = true; + } + } } else { owHeader = (OWVariablesHeader *)_ofImage; if (!validateOWChecksum(_ofImage)) { @@ -506,6 +710,9 @@ IOReturn IODTNVRAM::syncOFVariables(void) tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject()); if (tmpSymbol == 0) break; + // Don't save 'aapl,panic-info'. + if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) continue; + tmpObject = _ofDict->getObject(tmpSymbol); length = maxLength;