/* * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 2.0 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include // IOPCIAddressSpace #include #include "AppleSMBIOS.h" #if DEBUG #define DEBUG_LOG(args...) IOLog(args) #else #define DEBUG_LOG(args...) #endif //--------------------------------------------------------------------------- // SMBPackedStrings class class SMBPackedStrings { protected: const char * _start; const char * _limit; public: SMBPackedStrings( const SMBStructHeader * header, const void * limit ); const char * stringAtIndex( UInt8 index, UInt8 * length = 0 ) const; void setDataProperty( IORegistryEntry * entry, const char * key, UInt8 index ) const; void setStringProperty( IORegistryEntry * entry, const char * key, UInt8 index ) const; }; SMBPackedStrings::SMBPackedStrings( const SMBStructHeader * header, const void * limit ) { _start = (const char *) header + header->length; _limit = (const char *) limit; } const char * SMBPackedStrings::stringAtIndex( UInt8 index, UInt8 * length ) const { const char * last = 0; const char * next = _start; if ( length ) *length = 0; while ( index-- ) { last = 0; for ( const char * cp = next; cp < _limit; cp++ ) { if ( *cp == '\0' ) { last = next; next = cp + 1; break; } } if ( last == 0 ) break; } if ( last ) { while (*last == ' ') last++; if (length) { UInt8 len; for ( len = next - last - 1; len && last[len - 1] == ' '; len-- ) ; *length = len; // number of chars not counting the terminating NULL } } return last ? last : ""; } void SMBPackedStrings::setDataProperty( IORegistryEntry * entry, const char * key, UInt8 index ) const { UInt8 length; const char * string = SMBPackedStrings::stringAtIndex(index, &length); if (length) { OSData * data = OSData::withCapacity(length + 1); if (data) { data->appendBytes(string, length); data->appendByte('\0', 1); entry->setProperty(key, data); data->release(); } } } void SMBPackedStrings::setStringProperty( IORegistryEntry * entry, const char * key, UInt8 index ) const { UInt8 length; const char * string = SMBPackedStrings::stringAtIndex(index, &length); if (length) { OSString * strObj = OSString::withCString(string); if (strObj) { entry->setProperty(key, strObj); strObj->release(); } } } #define super IOService OSDefineMetaClassAndStructors( AppleSMBIOS, IOService ) //--------------------------------------------------------------------------- bool AppleSMBIOS::start( IOService * provider ) { OSSerializer * serializer; if (super::start(provider) != true || IOService::getResourceService() == 0 || IOService::getResourceService()->getProperty("SMBIOS")) { return false; } fSlotQueueHead = IONew(queue_head_t, 1); if (!fSlotQueueHead) return false; queue_init(fSlotQueueHead); // Get the IOPlatformExpertDevice fRoot = getServiceRoot(); if (!provider || !fRoot) return false; // Serialize SMBIOS data to user-space on demand serializer = OSSerializer::forTarget((void *) this, &serializeSMBIOS); if (!serializer) return false; setProperty("SMBIOS", serializer); fVerbose = 0; PE_parse_boot_arg("smbios", &fVerbose); memInfoSource = kNoMemoryInfo; memSlotsData = OSData::withCapacity(kMemDataSize); memTypesData = OSData::withCapacity(kMemDataSize); memSizesData = OSData::withCapacity(kMemDataSize); memSpeedData = OSData::withCapacity(kMemDataSize); memInfoData = OSData::withCapacity(kMemDataSize); memSizeTotal = 0; if (!memSlotsData || !memTypesData || !memSizesData || !memSpeedData || !memInfoData) return false; if (!findSMBIOSTableEFI()) { return false; } // Update device tree updateDeviceTree(); publishResource("SMBIOS"); registerService(); return true; } //--------------------------------------------------------------------------- #define RELEASE(x) do { if (x) { (x)->release(); (x) = 0; } } while(0) void AppleSMBIOS::free( void ) { RELEASE( memSlotsData ); RELEASE( memTypesData ); RELEASE( memSizesData ); RELEASE( memSpeedData ); RELEASE( memInfoData ); RELEASE( fDMIMemoryMap ); if (fSlotQueueHead) { SystemSlotEntry * slotEntry; while (!queue_empty(fSlotQueueHead)) { queue_remove_first(fSlotQueueHead, slotEntry, SystemSlotEntry *, chain); IODelete(slotEntry, SystemSlotEntry, 1); } IODelete(fSlotQueueHead, queue_head_t, 1); fSlotQueueHead = 0; } super::free(); } //--------------------------------------------------------------------------- bool AppleSMBIOS:: serializeSMBIOS( void * target, void * refcon, OSSerialize * s ) { AppleSMBIOS * me = (AppleSMBIOS *) target; OSData * data; IOMemoryMap * map; bool ok = false; map = me->fDMIMemoryMap; if (map) { data = OSData::withBytesNoCopy( (void *) map->getVirtualAddress(), map->getLength()); if (data) { ok = data->serialize(s); data->release(); } } return ok; } //--------------------------------------------------------------------------- static UInt8 checksum8( void * start, UInt length ) { UInt8 csum = 0; UInt8 * cp = (UInt8 *) start; for (UInt i = 0; i < length; i++) csum += *cp++; return csum; } #define kGenericPCISlotName "PCI Slot" //--------------------------------------------------------------------------- OSData * AppleSMBIOS:: getSlotNameWithSlotId( int slotId ) { char name[80]; SystemSlotEntry * slot = 0; SystemSlotEntry * iter; queue_iterate(fSlotQueueHead, iter, SystemSlotEntry *, chain) { if ((iter->slotID & 0xff) == slotId) { slot = iter; break; } } if (slot && slot->slotName) { strncpy(name, slot->slotName, sizeof(name)); } else { // No matching SlotId, return a generic PCI slot name snprintf(name, sizeof(name), "%s %u", kGenericPCISlotName, slotId); } name[sizeof(name) - 1] = '\0'; return OSData::withBytes(name, strlen(name) + 1); } #define EFI_SMBIOS_TABLE \ "/efi/configuration-table/EB9D2D31-2D88-11D3-9A16-0090273FC14D" //--------------------------------------------------------------------------- bool AppleSMBIOS::findSMBIOSTableEFI( void ) { IORegistryEntry * tableEntry; OSData * tableData; UInt64 tableAddr; IOMemoryDescriptor * epsMemory; SMBEntryPoint eps; IOMemoryDescriptor * dmiMemory = 0; IOItemCount dmiStructureCount = 0; tableEntry = fromPath(EFI_SMBIOS_TABLE, gIODTPlane); if (tableEntry) { tableAddr = 0; tableData = OSDynamicCast(OSData, tableEntry->getProperty("table")); if (tableData && (tableData->getLength() <= sizeof(tableAddr))) { bcopy(tableData->getBytesNoCopy(), &tableAddr, tableData->getLength()); epsMemory = IOMemoryDescriptor::withAddress( (mach_vm_address_t) tableAddr, (mach_vm_size_t) sizeof(eps), kIODirectionOutIn, NULL ); if (epsMemory) { bzero(&eps, sizeof(eps)); epsMemory->readBytes(0, &eps, sizeof(eps)); if (memcmp(eps.anchor, "_SM_", 4) == 0) { UInt8 csum; csum = checksum8(&eps, sizeof(eps)); DEBUG_LOG("DMI checksum = 0x%x\n", csum); DEBUG_LOG("DMI tableLength = %d\n", eps.dmi.tableLength); DEBUG_LOG("DMI tableAddress = 0x%lx\n", eps.dmi.tableAddress); DEBUG_LOG("DMI structureCount = %d\n", eps.dmi.structureCount); DEBUG_LOG("DMI bcdRevision = %x\n", eps.dmi.bcdRevision); if (csum == 0 && eps.dmi.tableLength && eps.dmi.structureCount) { dmiStructureCount = eps.dmi.structureCount; dmiMemory = IOMemoryDescriptor::withPhysicalAddress( eps.dmi.tableAddress, eps.dmi.tableLength, kIODirectionOutIn ); } else { DEBUG_LOG("No DMI structure found\n"); } } epsMemory->release(); epsMemory = 0; } } tableEntry->release(); } if ( dmiMemory ) { fDMIMemoryMap = dmiMemory->map(); if (fDMIMemoryMap) { decodeSMBIOSTable((void *) fDMIMemoryMap->getVirtualAddress(), fDMIMemoryMap->getLength(), dmiStructureCount ); } dmiMemory->release(); dmiMemory = 0; } return (fDMIMemoryMap != 0); } //--------------------------------------------------------------------------- void AppleSMBIOS:: adjustPCIDeviceEFI( IOService * pciDevice ) { IOACPIPlatformDevice * acpiDevice; UInt32 slotNum; OSString * acpiPath; IORegistryEntry * acpiEntry = NULL; // Does PCI device have an ACPI alias? // N : not built-in, no slot name, exit // Y : goto next // // Does ACPI device have a _SUN object? // N : it's a built in PCI device // Y : indicates a slot (not built-in), goto next // // Match _SUN value against SlotId in SMBIOS PCI slot structures do { acpiPath = OSDynamicCast(OSString, pciDevice->getProperty("acpi-path")); if (!acpiPath) break; acpiEntry = fromPath(acpiPath->getCStringNoCopy()); if (!acpiEntry) break; if (!acpiEntry->metaCast("IOACPIPlatformDevice")) break; acpiDevice = (IOACPIPlatformDevice *) acpiEntry; if (acpiDevice->evaluateInteger("_SUN", &slotNum) == kIOReturnSuccess) { OSObject * name = getSlotNameWithSlotId(slotNum); if (name) { pciDevice->setProperty("AAPL,slot-name", name); name->release(); } } else if (acpiDevice->validateObject("_RMV") == kIOReturnSuccess) { // no slot name? } else { char dummy = '\0'; pciDevice->setProperty("built-in", &dummy, 1); } } while (false); if (acpiEntry) acpiEntry->release(); } #pragma mark - //--------------------------------------------------------------------------- IOReturn AppleSMBIOS:: callPlatformFunction( const char * functionName, bool waitForFunction, void * param1, void * param2, void * param3, void * param4 ) { if (!functionName) return kIOReturnBadArgument; // AdjustPCIBridge function is called by the ACPI // platform driver, but is not useful on EFI systems. if (!strcmp(functionName, "AdjustPCIDevice")) { IOService * device = (IOService *) param1; if (device) { adjustPCIDeviceEFI(device); return kIOReturnSuccess; } } return kIOReturnUnsupported; } //--------------------------------------------------------------------------- void AppleSMBIOS::decodeSMBIOSTable( const void * tableData, UInt16 tableLength, UInt16 structureCount ) { const SMBStructHeader * header; const UInt8 * next = (const UInt8 *) tableData; const UInt8 * end = next + tableLength; while ( structureCount-- && (end > next + sizeof(SMBStructHeader)) ) { header = (const SMBStructHeader *) next; if (header->length > end - next) break; decodeSMBIOSStructure( header, end ); // Skip the formatted area of the structure. next += header->length; // Skip the unformatted structure area at the end (strings). // Look for a terminating double NULL. for ( ; end > next + sizeof(SMBStructHeader); next++ ) { if ( next[0] == 0 && next[1] == 0 ) { next += 2; break; } } } } //--------------------------------------------------------------------------- void AppleSMBIOS:: decodeSMBIOSStructure( const SMBStructHeader * structureHeader, const void * tableBoundary ) { const union SMBStructUnion { SMBBIOSInformation bios; SMBSystemInformation system; SMBSystemEnclosure enclosure; SMBProcessorInformation cpu; SMBCacheInformation cache; SMBPhysicalMemoryArray memoryArray; SMBMemoryDevice memoryDevice; SMBMemoryModule memoryModule; SMBSystemSlot slot; SMBFirmwareVolume fv; } * u = (const SMBStructUnion *) structureHeader; SMBPackedStrings strings = SMBPackedStrings( structureHeader, tableBoundary ); switch ( structureHeader->type ) { case kSMBTypeBIOSInformation: processSMBIOSStructure( &u->bios, &strings ); break; case kSMBTypeSystemInformation: processSMBIOSStructure( &u->system, &strings ); break; case kSMBTypeProcessorInformation: processSMBIOSStructure( &u->cpu, &strings ); break; case kSMBTypeCacheInformation: processSMBIOSStructure( &u->cache, &strings ); break; case kSMBTypeMemoryDevice: processSMBIOSStructure( &u->memoryDevice, &strings ); break; case kSMBTypeMemoryModule: processSMBIOSStructure( &u->memoryModule, &strings ); break; case kSMBTypeSystemSlot: processSMBIOSStructure( &u->slot, &strings ); break; case kSMBFirmwareVolume: processSMBIOSStructure( &u->fv, &strings ); break; } } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBBIOSInformation * bios, SMBPackedStrings * strings ) { char location[9]; if (bios->header.length < sizeof(SMBBIOSInformation)) return; if (!fROMNode) { fROMNode = OSTypeAlloc( IOService ); if (fROMNode && (false == fROMNode->init())) { fROMNode->release(); fROMNode = 0; } } if (fROMNode) { sprintf(location, "%x", bios->startSegment << 4); fROMNode->setLocation(location); strings->setDataProperty(fROMNode, "vendor", bios->vendor); strings->setDataProperty(fROMNode, "version", bios->version); strings->setDataProperty(fROMNode, "release-date", bios->releaseDate); strings->setDataProperty(fROMNode, "characteristics", bios->characteristics); fROMNode->setProperty("rom-size", (bios->romSize + 1) * 0x10000, 32 ); } } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBSystemInformation * sys, SMBPackedStrings * strings ) { UInt8 length; if (sys->header.length < 8) return; strings->setDataProperty(fRoot, "manufacturer", sys->manufacturer); strings->setDataProperty(fRoot, "product-name", sys->productName); strings->setDataProperty(fRoot, "version", sys->version); const char *serialNumberString = strings->stringAtIndex(sys->serialNumber, &length); // The serial-number property in the IORegistry is a 43-byte data object. // Bytes 0 through 2 are the last three bytes of the serial number string. // Bytes 11 through 20, inclusive, are the serial number string itself. // All other bytes are '\0'. OSData * data = OSData::withCapacity(43); if (data) { data->appendBytes(serialNumberString + (length - 3), 3); data->appendBytes(NULL, 10); data->appendBytes(serialNumberString, length); data->appendBytes(NULL, 43 - length - 10 - 3); fRoot->setProperty("serial-number", data); data->release(); } strings->setStringProperty(fRoot, kIOPlatformSerialNumberKey, sys->serialNumber); if (fVerbose) { IOLog("--- SMBIOS System Information --\n"); IOLog("manufacturer = %s\n", strings->stringAtIndex(sys->manufacturer)); IOLog("productName = %s\n", strings->stringAtIndex(sys->productName)); IOLog("version = %s\n", strings->stringAtIndex(sys->version)); IOLog("serialNumber = %s\n", strings->stringAtIndex(sys->serialNumber)); } } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBProcessorInformation * cpu, SMBPackedStrings * strings ) { if (cpu->header.length < 26) return; if (fVerbose) { IOLog("--- SMBIOS Processor Information --\n"); IOLog("socketDesignation = %s\n", strings->stringAtIndex(cpu->socketDesignation)); IOLog("processorType = 0x%x\n", cpu->processorType); IOLog("processorFamily = 0x%x\n", cpu->processorFamily); IOLog("manufacturer = %s\n", strings->stringAtIndex(cpu->manufacturer)); IOLog("processorID = 0x%lx%08lx\n", (UInt32)(cpu->processorID >> 32), (UInt32)cpu->processorID); IOLog("processorVersion = %s\n", strings->stringAtIndex(cpu->processorVersion)); IOLog("voltage = 0x%x\n", cpu->voltage); IOLog("externalClock = 0x%x\n", cpu->externalClock); IOLog("maximumClock = 0x%x\n", cpu->maximumClock); IOLog("currentClock = 0x%x\n", cpu->currentClock); IOLog("status = 0x%x\n", cpu->status); IOLog("processorUpgrade = 0x%x\n", cpu->processorUpgrade); } UInt32 busClockRateMHz = cpu->externalClock; UInt32 maxClockRateMHz = cpu->maximumClock; if (busClockRateMHz > 0) { i386_cpu_info_t * cpuinfo = cpuid_info(); IOService * platform = getPlatform(); if (!strncmp(cpuinfo->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)) && (cpuinfo->cpuid_features & CPUID_FEATURE_SSE2)) { // convert from FSB to quad-pumped bus speed busClockRateMHz *= 4; } platform->callPlatformFunction( "SetBusClockRateMHz", /* function */ false, /* waitForFunction */ (void *) busClockRateMHz, /* speed in MHz */ (void *) maxClockRateMHz, 0, 0); } } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBCacheInformation * cache, SMBPackedStrings * strings ) { if (fVerbose) { IOLog("--- SMBIOS Cache Information --\n"); IOLog("cache socket = %s\n", strings->stringAtIndex(cache->socketDesignation)); IOLog("cache config = 0x%x\n", cache->cacheConfiguration); IOLog("max cache size = 0x%x\n", cache->maximumCacheSize); IOLog("installed size = 0x%x\n", cache->installedSize); } } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBSystemSlot * slot, SMBPackedStrings * strings ) { SystemSlotEntry * slotEntry; if (slot->header.length < 12) return; slotEntry = IONew(SystemSlotEntry, 1); if (slotEntry) { memset(slotEntry, 0, sizeof(*slotEntry)); slotEntry->slotID = slot->slotID; slotEntry->slotType = slot->slotType; slotEntry->slotUsage = slot->currentUsage; slotEntry->slotName = strings->stringAtIndex(slot->slotDesignation); queue_enter(fSlotQueueHead, slotEntry, SystemSlotEntry *, chain); } DEBUG_LOG("Slot type %x, width %x, usage %x, ID %x, char1 %x\n", slot->slotType, slot->slotDataBusWidth, slot->currentUsage, slot->slotID, slot->slotCharacteristics1); } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBMemoryDevice * memory, SMBPackedStrings * strings ) { UInt8 deviceLocatorLength; const char * deviceLocatorString; UInt8 bankLocatorLength; const char * bankLocatorString; UInt8 memoryType; union { UInt64 ull; UInt32 ul[2]; } memoryBytes; if (memory->header.length < 21) return; if (memory->memorySize == 0) return; if (memInfoSource == kMemoryModuleInfo) { memSlotsData->initWithCapacity(kMemDataSize); memTypesData->initWithCapacity(kMemDataSize); memSizesData->initWithCapacity(kMemDataSize); memSpeedData->initWithCapacity(kMemDataSize); memSizeTotal = 0; } memInfoSource = kMemoryDeviceInfo; // update memSlotsData deviceLocatorString = strings->stringAtIndex( memory->deviceLocator, &deviceLocatorLength ); bankLocatorString = strings->stringAtIndex( memory->bankLocator, &bankLocatorLength ); if (!memory->deviceLocator) { deviceLocatorString = "Location"; deviceLocatorLength = strlen(deviceLocatorString); } if (!memory->bankLocator) { bankLocatorString = "Bank"; bankLocatorLength = strlen(bankLocatorString); } if ( deviceLocatorLength || bankLocatorString ) { if ( memSlotsData->getLength() == 0 ) memSlotsData->appendBytes(" ", 4); if ( bankLocatorLength ) memSlotsData->appendBytes( bankLocatorString, bankLocatorLength ); if ( deviceLocatorLength && bankLocatorLength ) memSlotsData->appendByte('/', 1); if ( deviceLocatorLength ) memSlotsData->appendBytes( deviceLocatorString, deviceLocatorLength ); memSlotsData->appendByte('\0', 1); } // update memTypesData #if 0 // disabled, information adds little value for ( int bit = 15; bit >= 0; bit-- ) { if ( ( memory->memoryTypeDetail & (1 << bit) ) && ( SMBMemoryTypeDetailStringTable[bit] != NULL ) ) { memTypesData->appendBytes( SMBMemoryTypeDetailStringTable[bit], strlen(SMBMemoryTypeDetailStringTable[bit])); memTypesData->appendByte( ' ', 1 ); } } #endif /* 0 */ memoryType = memory->memoryType; if ( memoryType > kSMBMemoryDeviceTypeCount - 1 ) memoryType = 0x02; // unknown type memTypesData->appendBytes( SMBMemoryDeviceTypes[memoryType], strlen(SMBMemoryDeviceTypes[memoryType]) + 1 ); // update memSizesData memoryBytes.ull = (memory->memorySize & 0x7fff) * 1024; if ((memory->memorySize & 0x8000) == 0) memoryBytes.ull *= 1024; memSizeTotal += memoryBytes.ull; memSizesData->appendBytes( &memoryBytes.ul[1], 4 ); memSizesData->appendBytes( &memoryBytes.ul[0], 4 ); if (memory->header.length >= 27) { char speedText[16]; if (memory->memorySpeed) { snprintf(speedText, sizeof(speedText), "%u MHz", memory->memorySpeed); memSpeedData->appendBytes(speedText, strlen(speedText) + 1); memInfoData->appendBytes(0, 128); } } // What about "available", "mem-info" prop? } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBMemoryModule * memory, SMBPackedStrings * strings ) { UInt8 socketLength; const char * socketString; UInt8 memorySize; union { UInt64 ull; UInt32 ul[2]; } memoryBytes; if (memory->header.length < sizeof(SMBMemoryModule)) return; if (memInfoSource == kMemoryDeviceInfo) return; memInfoSource = kMemoryModuleInfo; // update memSlotsData socketString = strings->stringAtIndex( memory->socketDesignation, &socketLength ); if ( socketString ) { if (memSlotsData->getLength() == 0) memSlotsData->appendBytes(" ", 4); if (socketLength) memSlotsData->appendBytes( socketString, socketLength ); memSlotsData->appendByte('\0', 1); } // update memTypesData memTypesData->appendBytes("DRAM", 5); // update memSizesData memorySize = memory->enabledSize & 0x7F; if (memorySize >= kSMBMemoryModuleSizeNotDeterminable) memoryBytes.ull = 0; else memoryBytes.ull = (1ULL << memorySize) * (1024 * 1024); memSizeTotal += memoryBytes.ull; memSizesData->appendBytes( &memoryBytes.ul[1], 4 ); memSizesData->appendBytes( &memoryBytes.ul[0], 4 ); } //--------------------------------------------------------------------------- void AppleSMBIOS:: processSMBIOSStructure( const SMBFirmwareVolume * fv, SMBPackedStrings * strings ) { const FW_REGION_INFO * regionInfo = NULL; if (fv->header.length < sizeof(SMBFirmwareVolume)) return; for (int i = 0; i < fv->RegionCount; i++) { if (fv->RegionType[i] == FW_REGION_MAIN) { regionInfo = &fv->FlashMap[i]; break; } } if (regionInfo && (regionInfo->EndAddress > regionInfo->StartAddress)) { if (!fROMNode) { fROMNode = OSTypeAlloc( IOService ); if (fROMNode && (false == fROMNode->init())) { fROMNode->release(); fROMNode = 0; } } if (fROMNode) { fROMNode->setProperty("fv-main-address", regionInfo->StartAddress, 32 ); fROMNode->setProperty("fv-main-size", regionInfo->EndAddress - regionInfo->StartAddress + 1, 32 ); } } } //--------------------------------------------------------------------------- void AppleSMBIOS::updateDeviceTree( void ) { IOService * memoryNode = OSTypeAlloc( IOService ); if (memoryNode && (false == memoryNode->init())) { memoryNode->release(); memoryNode = 0; } if (memoryNode) { memoryNode->setName("memory"); //memoryNode->setLocation("0"); memoryNode->setProperty( "slot-names", memSlotsData ); memoryNode->setProperty( "dimm-types", memTypesData ); memoryNode->setProperty( "reg", memSizesData ); if (memSpeedData->getLength()) { memoryNode->setProperty( "dimm-speeds", memSpeedData ); memoryNode->setProperty( "dimm-info", memInfoData ); } memoryNode->attachToParent( fRoot, gIODTPlane ); memoryNode->release(); } // Update max_mem kernel variable with the total size of installed RAM if (memSizeTotal && (memSizeTotal > max_mem)) { UInt32 bootMaxMem = 0; if (PE_parse_boot_arg("maxmem", &bootMaxMem) && bootMaxMem) { UInt64 limit = ((UInt64) bootMaxMem) * 1024ULL * 1024ULL; if (memSizeTotal > limit) memSizeTotal = limit; } max_mem = memSizeTotal; } if (fROMNode) { fROMNode->setName("rom"); fROMNode->attachToParent( fRoot, gIODTPlane ); fROMNode->release(); fROMNode = 0; } }