/* * 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. * * 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/intelmp.hh" #include "arch/x86/isa_traits.hh" #include "base/logging.hh" #include "base/types.hh" #include "mem/port_proxy.hh" #include "sim/byteswap.hh" // Config entry types #include "params/X86IntelMPBaseConfigEntry.hh" #include "params/X86IntelMPExtConfigEntry.hh" // General table structures #include "params/X86IntelMPConfigTable.hh" #include "params/X86IntelMPFloatingPointer.hh" // Base entry types #include "params/X86IntelMPBus.hh" #include "params/X86IntelMPIOAPIC.hh" #include "params/X86IntelMPIOIntAssignment.hh" #include "params/X86IntelMPLocalIntAssignment.hh" #include "params/X86IntelMPProcessor.hh" // Extended entry types #include "params/X86IntelMPAddrSpaceMapping.hh" #include "params/X86IntelMPBusHierarchy.hh" #include "params/X86IntelMPCompatAddrSpaceMod.hh" using namespace std; const char X86ISA::IntelMP::FloatingPointer::signature[] = "_MP_"; template uint8_t writeOutField(PortProxy& proxy, Addr addr, T val) { uint64_t guestVal = X86ISA::htog(val); proxy.writeBlob(addr, (uint8_t *)(&guestVal), sizeof(T)); uint8_t checkSum = 0; while (guestVal) { checkSum += guestVal; guestVal >>= 8; } return checkSum; } uint8_t writeOutString(PortProxy& proxy, Addr addr, string str, int length) { char cleanedString[length + 1]; cleanedString[length] = 0; if (str.length() > length) { memcpy(cleanedString, str.c_str(), length); warn("Intel MP configuration table string \"%s\" " "will be truncated to \"%s\".\n", str, (char *)&cleanedString); } else { memcpy(cleanedString, str.c_str(), str.length()); memset(cleanedString + str.length(), 0, length - str.length()); } proxy.writeBlob(addr, (uint8_t *)(&cleanedString), length); uint8_t checkSum = 0; for (int i = 0; i < length; i++) checkSum += cleanedString[i]; return checkSum; } Addr X86ISA::IntelMP::FloatingPointer::writeOut(PortProxy& proxy, Addr addr) { // Make sure that either a config table is present or a default // configuration was found but not both. if (!tableAddr && !defaultConfig) fatal("Either an MP configuration table or a default configuration " "must be used."); if (tableAddr && defaultConfig) fatal("Both an MP configuration table and a default configuration " "were set."); uint8_t checkSum = 0; proxy.writeBlob(addr, (uint8_t *)signature, 4); for (int i = 0; i < 4; i++) checkSum += signature[i]; checkSum += writeOutField(proxy, addr + 4, tableAddr); // The length of the structure in paragraphs, aka 16 byte chunks. uint8_t length = 1; proxy.writeBlob(addr + 8, &length, 1); checkSum += length; proxy.writeBlob(addr + 9, &specRev, 1); checkSum += specRev; proxy.writeBlob(addr + 11, &defaultConfig, 1); checkSum += defaultConfig; uint32_t features2_5 = imcrPresent ? (1 << 7) : 0; checkSum += writeOutField(proxy, addr + 12, features2_5); checkSum = -checkSum; proxy.writeBlob(addr + 10, &checkSum, 1); return 16; } X86ISA::IntelMP::FloatingPointer::FloatingPointer(Params * p) : SimObject(p), tableAddr(0), specRev(p->spec_rev), defaultConfig(p->default_config), imcrPresent(p->imcr_present) {} X86ISA::IntelMP::FloatingPointer * X86IntelMPFloatingPointerParams::create() { return new X86ISA::IntelMP::FloatingPointer(this); } Addr X86ISA::IntelMP::BaseConfigEntry::writeOut(PortProxy& proxy, Addr addr, uint8_t &checkSum) { proxy.writeBlob(addr, &type, 1); checkSum += type; return 1; } X86ISA::IntelMP::BaseConfigEntry::BaseConfigEntry(Params * p, uint8_t _type) : SimObject(p), type(_type) {} Addr X86ISA::IntelMP::ExtConfigEntry::writeOut(PortProxy& proxy, Addr addr, uint8_t &checkSum) { proxy.writeBlob(addr, &type, 1); checkSum += type; proxy.writeBlob(addr + 1, &length, 1); checkSum += length; return 1; } X86ISA::IntelMP::ExtConfigEntry::ExtConfigEntry(Params * p, uint8_t _type, uint8_t _length) : SimObject(p), type(_type), length(_length) {} const char X86ISA::IntelMP::ConfigTable::signature[] = "PCMP"; Addr X86ISA::IntelMP::ConfigTable::writeOut(PortProxy& proxy, Addr addr) { uint8_t checkSum = 0; proxy.writeBlob(addr, (uint8_t *)signature, 4); for (int i = 0; i < 4; i++) checkSum += signature[i]; // Base table length goes here but will be calculated later. proxy.writeBlob(addr + 6, (uint8_t *)(&specRev), 1); checkSum += specRev; // The checksum goes here but is still being calculated. checkSum += writeOutString(proxy, addr + 8, oemID, 8); checkSum += writeOutString(proxy, addr + 16, productID, 12); checkSum += writeOutField(proxy, addr + 28, oemTableAddr); checkSum += writeOutField(proxy, addr + 32, oemTableSize); checkSum += writeOutField(proxy, addr + 34, (uint16_t)baseEntries.size()); checkSum += writeOutField(proxy, addr + 36, localApic); uint8_t reserved = 0; proxy.writeBlob(addr + 43, &reserved, 1); checkSum += reserved; vector::iterator baseEnt; uint16_t offset = 44; for (baseEnt = baseEntries.begin(); baseEnt != baseEntries.end(); baseEnt++) { offset += (*baseEnt)->writeOut(proxy, addr + offset, checkSum); } // We've found the end of the base table this point. checkSum += writeOutField(proxy, addr + 4, offset); vector::iterator extEnt; uint16_t extOffset = 0; uint8_t extCheckSum = 0; for (extEnt = extEntries.begin(); extEnt != extEntries.end(); extEnt++) { extOffset += (*extEnt)->writeOut(proxy, addr + offset + extOffset, extCheckSum); } checkSum += writeOutField(proxy, addr + 40, extOffset); extCheckSum = -extCheckSum; checkSum += writeOutField(proxy, addr + 42, extCheckSum); // And now, we finally have the whole check sum completed. checkSum = -checkSum; writeOutField(proxy, addr + 7, checkSum); return offset + extOffset; }; X86ISA::IntelMP::ConfigTable::ConfigTable(Params * p) : SimObject(p), specRev(p->spec_rev), oemID(p->oem_id), productID(p->product_id), oemTableAddr(p->oem_table_addr), oemTableSize(p->oem_table_size), localApic(p->local_apic), baseEntries(p->base_entries), extEntries(p->ext_entries) {} X86ISA::IntelMP::ConfigTable * X86IntelMPConfigTableParams::create() { return new X86ISA::IntelMP::ConfigTable(this); } Addr X86ISA::IntelMP::Processor::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { BaseConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 1, localApicID); checkSum += writeOutField(proxy, addr + 2, localApicVersion); checkSum += writeOutField(proxy, addr + 3, cpuFlags); checkSum += writeOutField(proxy, addr + 4, cpuSignature); checkSum += writeOutField(proxy, addr + 8, featureFlags); uint32_t reserved = 0; proxy.writeBlob(addr + 12, (uint8_t *)(&reserved), 4); proxy.writeBlob(addr + 16, (uint8_t *)(&reserved), 4); return 20; } X86ISA::IntelMP::Processor::Processor(Params * p) : BaseConfigEntry(p, 0), localApicID(p->local_apic_id), localApicVersion(p->local_apic_version), cpuFlags(0), cpuSignature(0), featureFlags(p->feature_flags) { if (p->enable) cpuFlags |= (1 << 0); if (p->bootstrap) cpuFlags |= (1 << 1); replaceBits(cpuSignature, 0, 3, p->stepping); replaceBits(cpuSignature, 4, 7, p->model); replaceBits(cpuSignature, 8, 11, p->family); } X86ISA::IntelMP::Processor * X86IntelMPProcessorParams::create() { return new X86ISA::IntelMP::Processor(this); } Addr X86ISA::IntelMP::Bus::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { BaseConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 1, busID); checkSum += writeOutString(proxy, addr + 2, busType, 6); return 8; } X86ISA::IntelMP::Bus::Bus(Params * p) : BaseConfigEntry(p, 1), busID(p->bus_id), busType(p->bus_type) {} X86ISA::IntelMP::Bus * X86IntelMPBusParams::create() { return new X86ISA::IntelMP::Bus(this); } Addr X86ISA::IntelMP::IOAPIC::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { BaseConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 1, id); checkSum += writeOutField(proxy, addr + 2, version); checkSum += writeOutField(proxy, addr + 3, flags); checkSum += writeOutField(proxy, addr + 4, address); return 8; } X86ISA::IntelMP::IOAPIC::IOAPIC(Params * p) : BaseConfigEntry(p, 2), id(p->id), version(p->version), flags(0), address(p->address) { if (p->enable) flags |= 1; } X86ISA::IntelMP::IOAPIC * X86IntelMPIOAPICParams::create() { return new X86ISA::IntelMP::IOAPIC(this); } Addr X86ISA::IntelMP::IntAssignment::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { BaseConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 1, interruptType); checkSum += writeOutField(proxy, addr + 2, flags); checkSum += writeOutField(proxy, addr + 4, sourceBusID); checkSum += writeOutField(proxy, addr + 5, sourceBusIRQ); checkSum += writeOutField(proxy, addr + 6, destApicID); checkSum += writeOutField(proxy, addr + 7, destApicIntIn); return 8; } X86ISA::IntelMP::IOIntAssignment::IOIntAssignment(Params * p) : IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 3, p->source_bus_id, p->source_bus_irq, p->dest_io_apic_id, p->dest_io_apic_intin) {} X86ISA::IntelMP::IOIntAssignment * X86IntelMPIOIntAssignmentParams::create() { return new X86ISA::IntelMP::IOIntAssignment(this); } X86ISA::IntelMP::LocalIntAssignment::LocalIntAssignment(Params * p) : IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 4, p->source_bus_id, p->source_bus_irq, p->dest_local_apic_id, p->dest_local_apic_intin) {} X86ISA::IntelMP::LocalIntAssignment * X86IntelMPLocalIntAssignmentParams::create() { return new X86ISA::IntelMP::LocalIntAssignment(this); } Addr X86ISA::IntelMP::AddrSpaceMapping::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { ExtConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 2, busID); checkSum += writeOutField(proxy, addr + 3, addrType); checkSum += writeOutField(proxy, addr + 4, addr); checkSum += writeOutField(proxy, addr + 12, addrLength); return length; } X86ISA::IntelMP::AddrSpaceMapping::AddrSpaceMapping(Params * p) : ExtConfigEntry(p, 128, 20), busID(p->bus_id), addrType(p->address_type), addr(p->address), addrLength(p->length) {} X86ISA::IntelMP::AddrSpaceMapping * X86IntelMPAddrSpaceMappingParams::create() { return new X86ISA::IntelMP::AddrSpaceMapping(this); } Addr X86ISA::IntelMP::BusHierarchy::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { ExtConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 2, busID); checkSum += writeOutField(proxy, addr + 3, info); checkSum += writeOutField(proxy, addr + 4, parentBus); uint32_t reserved = 0; proxy.writeBlob(addr + 5, (uint8_t *)(&reserved), 3); return length; } X86ISA::IntelMP::BusHierarchy::BusHierarchy(Params * p) : ExtConfigEntry(p, 129, 8), busID(p->bus_id), info(0), parentBus(p->parent_bus) { if (p->subtractive_decode) info |= 1; } X86ISA::IntelMP::BusHierarchy * X86IntelMPBusHierarchyParams::create() { return new X86ISA::IntelMP::BusHierarchy(this); } Addr X86ISA::IntelMP::CompatAddrSpaceMod::writeOut( PortProxy& proxy, Addr addr, uint8_t &checkSum) { ExtConfigEntry::writeOut(proxy, addr, checkSum); checkSum += writeOutField(proxy, addr + 2, busID); checkSum += writeOutField(proxy, addr + 3, mod); checkSum += writeOutField(proxy, addr + 4, rangeList); return length; } X86ISA::IntelMP::CompatAddrSpaceMod::CompatAddrSpaceMod(Params * p) : ExtConfigEntry(p, 130, 8), busID(p->bus_id), mod(0), rangeList(p->range_list) { if (p->add) mod |= 1; } X86ISA::IntelMP::CompatAddrSpaceMod * X86IntelMPCompatAddrSpaceModParams::create() { return new X86ISA::IntelMP::CompatAddrSpaceMod(this); }