| /* |
| * 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<class T> |
| 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<BaseConfigEntry *>::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<ExtConfigEntry *>::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); |
| } |