From b03c95d075b74913313576e6e1fa4fc6b1f4dcb2 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 10 Oct 2008 23:39:53 -0700 Subject: X86: Create SimObjects in python and C++ to represent the Intel MP tables. --- src/arch/x86/X86System.py | 7 + src/arch/x86/bios/IntelMP.py | 233 +++++++++++++++++++++ src/arch/x86/bios/SConscript | 4 + src/arch/x86/bios/intelmp.cc | 476 +++++++++++++++++++++++++++++++++++++++++++ src/arch/x86/bios/intelmp.hh | 330 ++++++++++++++++++++++++++++++ src/arch/x86/system.cc | 50 ++++- src/arch/x86/system.hh | 10 + 7 files changed, 1104 insertions(+), 6 deletions(-) create mode 100644 src/arch/x86/bios/IntelMP.py create mode 100644 src/arch/x86/bios/intelmp.cc create mode 100644 src/arch/x86/bios/intelmp.hh (limited to 'src') diff --git a/src/arch/x86/X86System.py b/src/arch/x86/X86System.py index 5fe69c709..fc7a5acd0 100644 --- a/src/arch/x86/X86System.py +++ b/src/arch/x86/X86System.py @@ -56,12 +56,19 @@ from m5.params import * from E820 import X86E820Table, X86E820Entry from SMBios import X86SMBiosSMBiosTable +from IntelMP import X86IntelMPFloatingPointer, X86IntelMPConfigTable from System import System class X86System(System): type = 'X86System' smbios_table = Param.X86SMBiosSMBiosTable( X86SMBiosSMBiosTable(), 'table of smbios/dmi information') + intel_mp_pointer = Param.X86IntelMPFloatingPointer( + X86IntelMPFloatingPointer(), + 'intel mp spec floating pointer structure') + intel_mp_table = Param.X86IntelMPConfigTable( + X86IntelMPConfigTable(), + 'intel mp spec configuration table') class LinuxX86System(X86System): type = 'LinuxX86System' diff --git a/src/arch/x86/bios/IntelMP.py b/src/arch/x86/bios/IntelMP.py new file mode 100644 index 000000000..70e7963fa --- /dev/null +++ b/src/arch/x86/bios/IntelMP.py @@ -0,0 +1,233 @@ +# Copyright (c) 2008 The Hewlett-Packard Development Company +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the +# following conditions are met: +# +# The software must be used only for Non-Commercial Use which means any +# use which is NOT directed to receiving any direct monetary +# compensation for, or commercial advantage from such use. Illustrative +# examples of non-commercial use are academic research, personal study, +# teaching, education and corporate research & development. +# Illustrative examples of commercial use are distributing products for +# commercial advantage and providing services using the software for +# commercial advantage. +# +# If you wish to use this software or functionality therein that may be +# covered by patents for commercial use, please contact: +# Director of Intellectual Property Licensing +# Office of Strategy and Technology +# Hewlett-Packard Company +# 1501 Page Mill Road +# Palo Alto, California 94304 +# +# 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 HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. No right of +# sublicense is granted herewith. Derivatives of the software and +# output created using the software may be prepared, but only for +# Non-Commercial Uses. Derivatives of the software may be shared with +# others provided: (i) the others agree to abide by the list of +# conditions herein which includes the Non-Commercial Use restrictions; +# and (ii) such Derivatives of the software include the above copyright +# notice to acknowledge the contribution from this software where +# applicable, this list of conditions and the disclaimer below. +# +# 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 + +from m5.params import * +from m5.SimObject import SimObject + +class X86IntelMPFloatingPointer(SimObject): + type = 'X86IntelMPFloatingPointer' + cxx_class = 'X86ISA::IntelMP::FloatingPointer' + + # The minor revision of the spec to support. The major version is assumed + # to be 1 in accordance with the spec. + spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported') + # If no default configuration is used, set this to 0. + default_config = Param.UInt8(0, 'which default configuration to use') + imcr_present = Param.Bool(True, + 'whether the IMCR register is present in the APIC') + +class X86IntelMPConfigTable(SimObject): + type = 'X86IntelMPConfigTable' + cxx_class = 'X86ISA::IntelMP::ConfigTable' + + spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported') + oem_id = Param.String("", 'system manufacturer') + product_id = Param.String("", 'product family') + oem_table_addr = Param.UInt32(0, + 'pointer to the optional oem configuration table') + oem_table_size = Param.UInt16(0, 'size of the oem configuration table') + local_apic = Param.UInt32(0xFEE00000, 'address of the local APIC') + + base_entries = VectorParam.X86IntelMPBaseConfigEntry([], + 'base configuration table entries') + + ext_entries = VectorParam.X86IntelMPExtConfigEntry([], + 'extended configuration table entries') + +class X86IntelMPBaseConfigEntry(SimObject): + type = 'X86IntelMPBaseConfigEntry' + cxx_class = 'X86ISA::IntelMP::BaseConfigEntry' + abstract = True + +class X86IntelMPExtConfigEntry(SimObject): + type = 'X86IntelMPExtConfigEntry' + cxx_class = 'X86ISA::IntelMP::ExtConfigEntry' + abstract = True + +class X86IntelMPProcessor(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPProcessor' + cxx_class = 'X86ISA::IntelMP::Processor' + + local_apic_id = Param.UInt8(0, 'local APIC id') + local_apic_version = Param.UInt8(0, + 'bits 0-7 of the local APIC version register') + enable = Param.Bool(True, 'if this processor is usable') + bootstrap = Param.Bool(False, 'if this is the bootstrap processor') + + stepping = Param.UInt8(0) + model = Param.UInt8(0) + family = Param.UInt8(0) + + feature_flags = Param.UInt32(0, 'flags returned by the CPUID instruction') + +class X86IntelMPBus(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPBus' + cxx_class = 'X86ISA::IntelMP::Bus' + + bus_id = Param.UInt8(0, 'bus id assigned by the bios') + bus_type = Param.String("", 'string that identify the bus type') + # Legal values for bus_type are: + # + # "CBUS", "CBUSII", "EISA", "FUTURE", "INTERN", "ISA", "MBI", "MBII", + # "MCA", "MPI", "MPSA", "NUBUS", "PCI", "PCMCIA", "TC", "VL", "VME", + # "XPRESS" + +class X86IntelMPIOAPIC(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPIOAPIC' + cxx_class = 'X86ISA::IntelMP::IOAPIC' + + id = Param.UInt8(0, 'id of this APIC') + version = Param.UInt8(0, 'bits 0-7 of the version register') + + enable = Param.Bool(True, 'if this APIC is usable') + + address = Param.UInt32(0xfec00000, 'address of this APIC') + +class X86IntelMPInterruptType(Enum): + map = {'INT' : 0, + 'NMI' : 1, + 'SMI' : 2, + 'ExtInt' : 3 + } + +class X86IntelMPPolarity(Enum): + map = {'ConformPolarity' : 0, + 'ActiveHigh' : 1, + 'ActiveLow' : 3 + } + +class X86IntelMPTriggerMode(Enum): + map = {'ConformTrigger' : 0, + 'EdgeTrigger' : 1, + 'LevelTrigger' : 3 + } + +class X86IntelMPIOIntAssignment(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPIOIntAssignment' + cxx_class = 'X86ISA::IntelMP::IOIntAssignment' + + interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt') + + polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity') + trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode') + + source_bus_id = Param.UInt8(0, + 'id of the bus from which the interrupt signal comes') + source_bus_irq = Param.UInt8(0, + 'which interrupt signal from the source bus') + + dest_io_apic_id = Param.UInt8(0, + 'id of the IO APIC the interrupt is going to') + dest_io_apic_intin = Param.UInt8(0, + 'the INTIN pin on the IO APIC the interrupt is connected to') + +class X86IntelMPLocalIntAssignment(X86IntelMPBaseConfigEntry): + type = 'X86IntelMPLocalIntAssignment' + cxx_class = 'X86ISA::IntelMP::LocalIntAssignment' + + interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt') + + polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity') + trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode') + + source_bus_id = Param.UInt8(0, + 'id of the bus from which the interrupt signal comes') + source_bus_irq = Param.UInt8(0, + 'which interrupt signal from the source bus') + + dest_local_apic_id = Param.UInt8(0, + 'id of the local APIC the interrupt is going to') + dest_local_apic_intin = Param.UInt8(0, + 'the INTIN pin on the local APIC the interrupt is connected to') + +class X86IntelMPAddressType(Enum): + map = {"IOAddress" : 0, + "MemoryAddress" : 1, + "PrefetchAddress" : 2 + } + +class X86IntelMPAddrSpaceMapping(X86IntelMPExtConfigEntry): + type = 'X86IntelMPAddrSpaceMapping' + cxx_class = 'X86ISA::IntelMP::AddrSpaceMapping' + + bus_id = Param.UInt8(0, 'id of the bus the address space is mapped to') + address_type = Param.X86IntelMPAddressType('IOAddress', + 'address type used to access bus') + address = Param.Addr(0, 'starting address of the mapping') + length = Param.UInt64(0, 'length of mapping in bytes') + +class X86IntelMPBusHierarchy(X86IntelMPExtConfigEntry): + type = 'X86IntelMPBusHierarchy' + cxx_class = 'X86ISA::IntelMP::BusHierarchy' + + bus_id = Param.UInt8(0, 'id of the bus being described') + subtractive_decode = Param.Bool(False, + 'whether this bus contains all addresses not used by its children') + parent_bus = Param.UInt8(0, 'bus id of this busses parent') + +class X86IntelMPRangeList(Enum): + map = {"ISACompatible" : 0, + "VGACompatible" : 1 + } + +class X86IntelMPCompatAddrSpaceMod(X86IntelMPExtConfigEntry): + type = 'X86IntelMPCompatAddrSpaceMod' + cxx_class = 'X86ISA::IntelMP::CompatAddrSpaceMod' + + bus_id = Param.UInt8(0, 'id of the bus being described') + add = Param.Bool(False, + 'if the range should be added to the original mapping') + range_list = Param.X86IntelMPRangeList('ISACompatible', + 'which predefined range of addresses to use') diff --git a/src/arch/x86/bios/SConscript b/src/arch/x86/bios/SConscript index cdb5f390f..c4f4f80e6 100644 --- a/src/arch/x86/bios/SConscript +++ b/src/arch/x86/bios/SConscript @@ -67,3 +67,7 @@ if env['TARGET_ISA'] == 'x86': # The DMI tables. SimObject('SMBios.py') Source('smbios.cc') + + # Intel Multiprocessor Specification Configuration Table + SimObject('IntelMP.py') + Source('intelmp.cc') diff --git a/src/arch/x86/bios/intelmp.cc b/src/arch/x86/bios/intelmp.cc new file mode 100644 index 000000000..2332e7a5c --- /dev/null +++ b/src/arch/x86/bios/intelmp.cc @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * 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 HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * 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/misc.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" +#include "sim/host.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(FunctionalPort * port, Addr addr, T val) +{ + T guestVal = X86ISA::htog(val); + port->writeBlob(addr, (uint8_t *)(&guestVal), sizeof(T)); + + uint8_t checkSum = 0; + while(guestVal) { + checkSum += guestVal; + guestVal >>= 8; + } + return checkSum; +} + +uint8_t +writeOutString(FunctionalPort * port, 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, cleanedString); + } else { + memcpy(cleanedString, str.c_str(), str.length()); + memset(cleanedString + str.length(), 0, length - str.length()); + } + port->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(FunctionalPort * port, 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; + + port->writeBlob(addr, (uint8_t *)signature, 4); + for (int i = 0; i < 4; i++) + checkSum += signature[i]; + + checkSum += writeOutField(port, addr + 4, tableAddr); + + // The length of the structure in paragraphs, aka 16 byte chunks. + uint8_t length = 1; + port->writeBlob(addr + 8, &length, 1); + checkSum += length; + + port->writeBlob(addr + 9, &specRev, 1); + checkSum += specRev; + + port->writeBlob(addr + 11, &defaultConfig, 1); + checkSum += defaultConfig; + + uint32_t features2_5 = imcrPresent ? (1 << 7) : 0; + checkSum += writeOutField(port, addr + 12, features2_5); + + checkSum = -checkSum; + port->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(FunctionalPort * port, + Addr addr, uint8_t &checkSum) +{ + port->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(FunctionalPort * port, + Addr addr, uint8_t &checkSum) +{ + port->writeBlob(addr, &type, 1); + checkSum += type; + port->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(FunctionalPort * port, Addr addr) +{ + uint8_t checkSum = 0; + + port->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. + + port->writeBlob(addr + 6, (uint8_t *)(&specRev), 1); + checkSum += specRev; + + // The checksum goes here but is still being calculated. + + checkSum += writeOutString(port, addr + 8, oemID, 8); + checkSum += writeOutString(port, addr + 16, productID, 12); + + checkSum += writeOutField(port, addr + 28, oemTableAddr); + checkSum += writeOutField(port, addr + 32, oemTableSize); + checkSum += writeOutField(port, addr + 34, (uint16_t)baseEntries.size()); + checkSum += writeOutField(port, addr + 36, localApic); + + uint8_t reserved = 0; + port->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(port, addr + offset, checkSum); + } + + // We've found the end of the base table this point. + checkSum += writeOutField(port, 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(port, + addr + offset + extOffset, extCheckSum); + } + + checkSum += writeOutField(port, addr + 40, extOffset); + extCheckSum = -extCheckSum; + checkSum += writeOutField(port, addr + 42, extCheckSum); + + // And now, we finally have the whole check sum completed. + checkSum = -checkSum; + writeOutField(port, 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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, localApicID); + checkSum += writeOutField(port, addr + 2, localApicVersion); + checkSum += writeOutField(port, addr + 3, cpuFlags); + checkSum += writeOutField(port, addr + 4, cpuSignature); + checkSum += writeOutField(port, addr + 8, featureFlags); + + uint32_t reserved = 0; + port->writeBlob(addr + 12, (uint8_t *)(&reserved), 4); + port->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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, busID); + checkSum += writeOutString(port, 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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, id); + checkSum += writeOutField(port, addr + 2, version); + checkSum += writeOutField(port, addr + 3, flags); + checkSum += writeOutField(port, 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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + BaseConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 1, interruptType); + checkSum += writeOutField(port, addr + 2, flags); + checkSum += writeOutField(port, addr + 4, sourceBusID); + checkSum += writeOutField(port, addr + 5, sourceBusIRQ); + checkSum += writeOutField(port, addr + 6, destApicID); + checkSum += writeOutField(port, 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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, addrType); + checkSum += writeOutField(port, addr + 4, addr); + checkSum += writeOutField(port, 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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, info); + checkSum += writeOutField(port, addr + 4, parentBus); + + uint32_t reserved = 0; + port->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( + FunctionalPort * port, Addr addr, uint8_t &checkSum) +{ + ExtConfigEntry::writeOut(port, addr, checkSum); + checkSum += writeOutField(port, addr + 2, busID); + checkSum += writeOutField(port, addr + 3, mod); + checkSum += writeOutField(port, 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); +} diff --git a/src/arch/x86/bios/intelmp.hh b/src/arch/x86/bios/intelmp.hh new file mode 100644 index 000000000..e8d1d656e --- /dev/null +++ b/src/arch/x86/bios/intelmp.hh @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2008 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * 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 HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * 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 + */ + +#ifndef __ARCH_X86_BIOS_INTELMP_HH__ +#define __ARCH_X86_BIOS_INTELMP_HH__ + +#include +#include + +#include "base/bitfield.hh" +#include "sim/sim_object.hh" + +#include "enums/X86IntelMPAddressType.hh" +#include "enums/X86IntelMPInterruptType.hh" +#include "enums/X86IntelMPPolarity.hh" +#include "enums/X86IntelMPRangeList.hh" +#include "enums/X86IntelMPTriggerMode.hh" + +class FunctionalPort; + +// Config entry types +class X86IntelMPBaseConfigEntryParams; +class X86IntelMPExtConfigEntryParams; + +// General table structures +class X86IntelMPConfigTableParams; +class X86IntelMPFloatingPointerParams; + +// Base entry types +class X86IntelMPBusParams; +class X86IntelMPIOAPICParams; +class X86IntelMPIOIntAssignmentParams; +class X86IntelMPLocalIntAssignmentParams; +class X86IntelMPProcessorParams; + +// Extended entry types +class X86IntelMPAddrSpaceMappingParams; +class X86IntelMPBusHierarchyParams; +class X86IntelMPCompatAddrSpaceModParams; + +namespace X86ISA +{ + +namespace IntelMP +{ + +class FloatingPointer : public SimObject +{ + protected: + typedef X86IntelMPFloatingPointerParams Params; + + uint32_t tableAddr; + uint8_t specRev; + uint8_t defaultConfig; + bool imcrPresent; + + static const char signature[]; + + public: + + Addr writeOut(FunctionalPort * port, Addr addr); + + Addr getTableAddr() + { + return tableAddr; + } + + void setTableAddr(Addr addr) + { + tableAddr = addr; + } + + FloatingPointer(Params * p); +}; + +class BaseConfigEntry : public SimObject +{ + protected: + typedef X86IntelMPBaseConfigEntryParams Params; + + uint8_t type; + + public: + + virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + BaseConfigEntry(Params * p, uint8_t _type); +}; + +class ExtConfigEntry : public SimObject +{ + protected: + typedef X86IntelMPExtConfigEntryParams Params; + + uint8_t type; + uint8_t length; + + public: + + virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + ExtConfigEntry(Params * p, uint8_t _type, uint8_t _length); +}; + +class ConfigTable : public SimObject +{ + protected: + typedef X86IntelMPConfigTableParams Params; + + static const char signature[]; + + uint8_t specRev; + std::string oemID; + std::string productID; + uint32_t oemTableAddr; + uint16_t oemTableSize; + uint32_t localApic; + + std::vector baseEntries; + std::vector extEntries; + + public: + Addr writeOut(FunctionalPort * port, Addr addr); + + ConfigTable(Params * p); +}; + +class Processor : public BaseConfigEntry +{ + protected: + typedef X86IntelMPProcessorParams Params; + + uint8_t localApicID; + uint8_t localApicVersion; + uint8_t cpuFlags; + uint32_t cpuSignature; + uint32_t featureFlags; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + Processor(Params * p); +}; + +class Bus : public BaseConfigEntry +{ + protected: + typedef X86IntelMPBusParams Params; + + uint8_t busID; + std::string busType; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + Bus(Params * p); +}; + +class IOAPIC : public BaseConfigEntry +{ + protected: + typedef X86IntelMPIOAPICParams Params; + + uint8_t id; + uint8_t version; + uint8_t flags; + uint32_t address; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + IOAPIC(Params * p); +}; + +class IntAssignment : public BaseConfigEntry +{ + protected: + uint8_t interruptType; + + uint16_t flags; + + uint8_t sourceBusID; + uint8_t sourceBusIRQ; + + uint8_t destApicID; + uint8_t destApicIntIn; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + IntAssignment(X86IntelMPBaseConfigEntryParams * p, + Enums::X86IntelMPInterruptType _interruptType, + Enums::X86IntelMPPolarity polarity, + Enums::X86IntelMPTriggerMode trigger, + uint8_t _type, + uint8_t _sourceBusID, uint8_t _sourceBusIRQ, + uint8_t _destApicID, uint8_t _destApicIntIn) : + BaseConfigEntry(p, _type), + interruptType(_interruptType), flags(0), + sourceBusID(_sourceBusID), sourceBusIRQ(_sourceBusIRQ), + destApicID(_destApicID), destApicIntIn(_destApicIntIn) + { + replaceBits(flags, 0, 1, polarity); + replaceBits(flags, 2, 3, trigger); + } +}; + +class IOIntAssignment : public IntAssignment +{ + protected: + typedef X86IntelMPIOIntAssignmentParams Params; + + public: + IOIntAssignment(Params * p); +}; + +class LocalIntAssignment : public IntAssignment +{ + protected: + typedef X86IntelMPLocalIntAssignmentParams Params; + + public: + LocalIntAssignment(Params * p); +}; + +class AddrSpaceMapping : public ExtConfigEntry +{ + protected: + typedef X86IntelMPAddrSpaceMappingParams Params; + + uint8_t busID; + uint8_t addrType; + uint64_t addr; + uint64_t addrLength; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + AddrSpaceMapping(Params * p); +}; + +class BusHierarchy : public ExtConfigEntry +{ + protected: + typedef X86IntelMPBusHierarchyParams Params; + + uint8_t busID; + uint8_t info; + uint8_t parentBus; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + BusHierarchy(Params * p); +}; + +class CompatAddrSpaceMod : public ExtConfigEntry +{ + protected: + typedef X86IntelMPCompatAddrSpaceModParams Params; + + uint8_t busID; + uint8_t mod; + uint32_t rangeList; + + public: + Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum); + + CompatAddrSpaceMod(Params * p); +}; + +} //IntelMP + +} //X86ISA + +#endif diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc index 9006ce227..b2fadd682 100644 --- a/src/arch/x86/system.cc +++ b/src/arch/x86/system.cc @@ -56,12 +56,14 @@ */ #include "arch/x86/bios/smbios.hh" +#include "arch/x86/bios/intelmp.hh" #include "arch/x86/miscregs.hh" #include "arch/x86/system.hh" #include "arch/vtophys.hh" -#include "base/remote_gdb.hh" +#include "base/intmath.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" +#include "base/remote_gdb.hh" #include "base/trace.hh" #include "cpu/thread_context.hh" #include "mem/physical.hh" @@ -72,8 +74,10 @@ using namespace LittleEndianGuest; using namespace X86ISA; -X86System::X86System(Params *p) - : System(p), smbiosTable(p->smbios_table) +X86System::X86System(Params *p) : + System(p), smbiosTable(p->smbios_table), + mpFloatingPointer(p->intel_mp_pointer), + mpConfigTable(p->intel_mp_table) {} void @@ -232,11 +236,16 @@ X86System::startup() // We should now be in long mode. Yay! Addr ebdaPos = 0xF0000; + Addr fixed, table; - Addr headerSize, structSize; //Write out the SMBios/DMI table - writeOutSMBiosTable(ebdaPos, headerSize, structSize); - ebdaPos += (headerSize + structSize); + writeOutSMBiosTable(ebdaPos, fixed, table); + ebdaPos += (fixed + table); + ebdaPos = roundUp(ebdaPos, 16); + + //Write out the Intel MP Specification configuration table + writeOutMPTable(ebdaPos, fixed, table); + ebdaPos += (fixed + table); } void @@ -260,6 +269,35 @@ X86System::writeOutSMBiosTable(Addr header, assert(table > header || table + structSize <= header); } +void +X86System::writeOutMPTable(Addr fp, + Addr &fpSize, Addr &tableSize, Addr table) +{ + // Get a port to write the table and header to memory. + FunctionalPort * physPort = threadContexts[0]->getPhysPort(); + + // If the table location isn't specified and it exists, just put + // it after the floating pointer. The fp size as of the 1.4 Intel MP + // specification is 0x10 bytes. + if (mpConfigTable) { + if (!table) + table = fp + 0x10; + mpFloatingPointer->setTableAddr(table); + } + + fpSize = mpFloatingPointer->writeOut(physPort, fp); + if (mpConfigTable) + tableSize = mpConfigTable->writeOut(physPort, table); + else + tableSize = 0; + + // Do some bounds checking to make sure we at least didn't step on + // ourselves and the fp structure was the size we thought it was. + assert(fp > table || fp + fpSize <= table); + assert(table > fp || table + tableSize <= fp); + assert(fpSize == 0x10); +} + X86System::~X86System() { diff --git a/src/arch/x86/system.hh b/src/arch/x86/system.hh index 2120bc090..7433cc644 100644 --- a/src/arch/x86/system.hh +++ b/src/arch/x86/system.hh @@ -74,6 +74,11 @@ namespace X86ISA { class SMBiosTable; } + namespace IntelMP + { + class FloatingPointer; + class ConfigTable; + } } class X86System : public System @@ -95,10 +100,15 @@ class X86System : public System protected: X86ISA::SMBios::SMBiosTable * smbiosTable; + X86ISA::IntelMP::FloatingPointer * mpFloatingPointer; + X86ISA::IntelMP::ConfigTable * mpConfigTable; void writeOutSMBiosTable(Addr header, Addr &headerSize, Addr &tableSize, Addr table = 0); + void writeOutMPTable(Addr fp, + Addr &fpSize, Addr &tableSize, Addr table = 0); + const Params *params() const { return (const Params *)_params; } virtual Addr fixFuncEventAddr(Addr addr) -- cgit v1.2.3