/* * Copyright (c) 2008 The Hewlett-Packard Development Company * All rights reserved. * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black */ #include "arch/x86/bios/smbios.hh" #include "arch/x86/isa_traits.hh" #include "base/types.hh" #include "mem/port_proxy.hh" #include "params/X86SMBiosBiosInformation.hh" #include "params/X86SMBiosSMBiosStructure.hh" #include "params/X86SMBiosSMBiosTable.hh" #include "sim/byteswap.hh" using namespace std; const char X86ISA::SMBios::SMBiosTable::SMBiosHeader::anchorString[] = "_SM_"; const uint8_t X86ISA::SMBios::SMBiosTable:: SMBiosHeader::formattedArea[] = {0,0,0,0,0}; const uint8_t X86ISA::SMBios::SMBiosTable:: SMBiosHeader::entryPointLength = 0x1F; const uint8_t X86ISA::SMBios::SMBiosTable:: SMBiosHeader::entryPointRevision = 0; const char X86ISA::SMBios::SMBiosTable:: SMBiosHeader::IntermediateHeader::anchorString[] = "_DMI_"; template uint64_t composeBitVector(T vec) { uint64_t val = 0; typename T::iterator vecIt; for (vecIt = vec.begin(); vecIt != vec.end(); vecIt++) { val |= (1 << (*vecIt)); } return val; } uint16_t X86ISA::SMBios::SMBiosStructure::writeOut(PortProxy& proxy, Addr addr) { proxy.writeBlob(addr, &type, 1); uint8_t length = getLength(); proxy.writeBlob(addr + 1, &length, 1); uint16_t handleGuest = X86ISA::htog(handle); proxy.writeBlob(addr + 2, &handleGuest, 2); return length + getStringLength(); } X86ISA::SMBios::SMBiosStructure::SMBiosStructure(Params * p, uint8_t _type) : SimObject(p), type(_type), handle(0), stringFields(false) {} void X86ISA::SMBios::SMBiosStructure::writeOutStrings( PortProxy& proxy, Addr addr) { std::vector::iterator it; Addr offset = 0; const uint8_t nullTerminator = 0; // If there are string fields but none of them are used, that's a // special case which is handled by this if. if (strings.size() == 0 && stringFields) { proxy.writeBlob(addr + offset, &nullTerminator, 1); offset++; } else { for (it = strings.begin(); it != strings.end(); it++) { proxy.writeBlob(addr + offset, it->c_str(), it->length() + 1); offset += it->length() + 1; } } proxy.writeBlob(addr + offset, &nullTerminator, 1); } int X86ISA::SMBios::SMBiosStructure::getStringLength() { int size = 0; std::vector::iterator it; for (it = strings.begin(); it != strings.end(); it++) { size += it->length() + 1; } return size + 1; } int X86ISA::SMBios::SMBiosStructure::addString(string & newString) { stringFields = true; // If a string is empty, treat it as not existing. The index for empty // strings is 0. if (newString.length() == 0) return 0; strings.push_back(newString); return strings.size(); } string X86ISA::SMBios::SMBiosStructure::readString(int n) { assert(n > 0 && n <= strings.size()); return strings[n - 1]; } void X86ISA::SMBios::SMBiosStructure::setString(int n, std::string & newString) { assert(n > 0 && n <= strings.size()); strings[n - 1] = newString; } X86ISA::SMBios::BiosInformation::BiosInformation(Params * p) : SMBiosStructure(p, Type), startingAddrSegment(p->starting_addr_segment), romSize(p->rom_size), majorVer(p->major), minorVer(p->minor), embContFirmwareMajor(p->emb_cont_firmware_major), embContFirmwareMinor(p->emb_cont_firmware_minor) { vendor = addString(p->vendor); version = addString(p->version); releaseDate = addString(p->release_date); characteristics = composeBitVector(p->characteristics); characteristicExtBytes = composeBitVector(p->characteristic_ext_bytes); } uint16_t X86ISA::SMBios::BiosInformation::writeOut(PortProxy& proxy, Addr addr) { uint8_t size = SMBiosStructure::writeOut(proxy, addr); proxy.writeBlob(addr + 0x4, &vendor, 1); proxy.writeBlob(addr + 0x5, &version, 1); uint16_t startingAddrSegmentGuest = X86ISA::htog(startingAddrSegment); proxy.writeBlob(addr + 0x6, &startingAddrSegmentGuest, 2); proxy.writeBlob(addr + 0x8, &releaseDate, 1); proxy.writeBlob(addr + 0x9, &romSize, 1); uint64_t characteristicsGuest = X86ISA::htog(characteristics); proxy.writeBlob(addr + 0xA, &characteristicsGuest, 8); uint16_t characteristicExtBytesGuest = X86ISA::htog(characteristicExtBytes); proxy.writeBlob(addr + 0x12, &characteristicExtBytesGuest, 2); proxy.writeBlob(addr + 0x14, &majorVer, 1); proxy.writeBlob(addr + 0x15, &minorVer, 1); proxy.writeBlob(addr + 0x16, &embContFirmwareMajor, 1); proxy.writeBlob(addr + 0x17, &embContFirmwareMinor, 1); writeOutStrings(proxy, addr + getLength()); return size; } X86ISA::SMBios::SMBiosTable::SMBiosTable(Params * p) : SimObject(p), structures(p->structures) { smbiosHeader.majorVersion = p->major_version; smbiosHeader.minorVersion = p->minor_version; assert(p->major_version <= 9); assert(p->minor_version <= 9); smbiosHeader.intermediateHeader.smbiosBCDRevision = (p->major_version << 4) | p->minor_version; } void X86ISA::SMBios::SMBiosTable::writeOut(PortProxy& proxy, Addr addr, Addr &headerSize, Addr &structSize) { headerSize = 0x1F; /* * The main header */ uint8_t mainChecksum = 0; proxy.writeBlob(addr, (uint8_t *)smbiosHeader.anchorString, 4); for (int i = 0; i < 4; i++) mainChecksum += smbiosHeader.anchorString[i]; // The checksum goes here, but we're figuring it out as we go. proxy.writeBlob(addr + 0x5, &smbiosHeader.entryPointLength, 1); mainChecksum += smbiosHeader.entryPointLength; proxy.writeBlob(addr + 0x6, &smbiosHeader.majorVersion, 1); mainChecksum += smbiosHeader.majorVersion; proxy.writeBlob(addr + 0x7, &smbiosHeader.minorVersion, 1); mainChecksum += smbiosHeader.minorVersion; // Maximum structure size goes here, but we'll figure it out later. proxy.writeBlob(addr + 0xA, &smbiosHeader.entryPointRevision, 1); mainChecksum += smbiosHeader.entryPointRevision; proxy.writeBlob(addr + 0xB, &smbiosHeader.formattedArea, 5); for (int i = 0; i < 5; i++) mainChecksum += smbiosHeader.formattedArea[i]; /* * The intermediate header */ uint8_t intChecksum = 0; proxy.writeBlob(addr + 0x10, smbiosHeader.intermediateHeader.anchorString, 5); for (int i = 0; i < 5; i++) intChecksum += smbiosHeader.intermediateHeader.anchorString[i]; // The checksum goes here, but we're figuring it out as we go. // Then the length of the structure table which we'll find later uint32_t tableAddrGuest = X86ISA::htog(smbiosHeader.intermediateHeader.tableAddr); proxy.writeBlob(addr + 0x18, &tableAddrGuest, 4); for (int i = 0; i < 4; i++) { intChecksum += tableAddrGuest; tableAddrGuest >>= 8; } uint16_t numStructs = X86ISA::gtoh(structures.size()); proxy.writeBlob(addr + 0x1C, &numStructs, 2); for (int i = 0; i < 2; i++) { intChecksum += numStructs; numStructs >>= 8; } proxy.writeBlob(addr + 0x1E, &smbiosHeader.intermediateHeader.smbiosBCDRevision, 1); intChecksum += smbiosHeader.intermediateHeader.smbiosBCDRevision; /* * Structure table */ Addr base = smbiosHeader.intermediateHeader.tableAddr; Addr offset = 0; uint16_t maxSize = 0; std::vector::iterator it; for (it = structures.begin(); it != structures.end(); it++) { uint16_t size = (*it)->writeOut(proxy, base + offset); if (size > maxSize) maxSize = size; offset += size; } structSize = offset; /* * Header */ maxSize = X86ISA::htog(maxSize); proxy.writeBlob(addr + 0x8, &maxSize, 2); for (int i = 0; i < 2; i++) { mainChecksum += maxSize; maxSize >>= 8; } // Set the checksum mainChecksum = -mainChecksum; proxy.writeBlob(addr + 0x4, &mainChecksum, 1); /* * Intermediate header */ uint16_t tableSize = offset; tableSize = X86ISA::htog(tableSize); proxy.writeBlob(addr + 0x16, &tableSize, 2); for (int i = 0; i < 2; i++) { intChecksum += tableSize; tableSize >>= 8; } intChecksum = -intChecksum; proxy.writeBlob(addr + 0x15, &intChecksum, 1); } X86ISA::SMBios::BiosInformation * X86SMBiosBiosInformationParams::create() { return new X86ISA::SMBios::BiosInformation(this); } X86ISA::SMBios::SMBiosTable * X86SMBiosSMBiosTableParams::create() { return new X86ISA::SMBios::SMBiosTable(this); }