1/* 2 * Copyright (c) 2008 The Hewlett-Packard Development Company 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Gabe Black 38 */ 39 40#include "arch/x86/bios/intelmp.hh" 41 42#include "arch/x86/isa_traits.hh" 43#include "base/logging.hh" 44#include "base/types.hh" 45#include "mem/port_proxy.hh" 46#include "sim/byteswap.hh" 47 48// Config entry types 49#include "params/X86IntelMPBaseConfigEntry.hh" 50#include "params/X86IntelMPExtConfigEntry.hh" 51 52// General table structures 53#include "params/X86IntelMPConfigTable.hh" 54#include "params/X86IntelMPFloatingPointer.hh" 55 56// Base entry types 57#include "params/X86IntelMPBus.hh" 58#include "params/X86IntelMPIOAPIC.hh" 59#include "params/X86IntelMPIOIntAssignment.hh" 60#include "params/X86IntelMPLocalIntAssignment.hh" 61#include "params/X86IntelMPProcessor.hh" 62 63// Extended entry types 64#include "params/X86IntelMPAddrSpaceMapping.hh" 65#include "params/X86IntelMPBusHierarchy.hh" 66#include "params/X86IntelMPCompatAddrSpaceMod.hh" 67 68using namespace std; 69 70const char X86ISA::IntelMP::FloatingPointer::signature[] = "_MP_"; 71 72template<class T> 73uint8_t 74writeOutField(PortProxy& proxy, Addr addr, T val) 75{ 76 uint64_t guestVal = X86ISA::htog(val); 77 proxy.writeBlob(addr, &guestVal, sizeof(T)); 78 79 uint8_t checkSum = 0; 80 while (guestVal) { 81 checkSum += guestVal; 82 guestVal >>= 8; 83 } 84 return checkSum; 85} 86 87uint8_t 88writeOutString(PortProxy& proxy, Addr addr, string str, int length) 89{ 90 char cleanedString[length + 1]; 91 cleanedString[length] = 0; 92 93 if (str.length() > length) { 94 memcpy(cleanedString, str.c_str(), length); 95 warn("Intel MP configuration table string \"%s\" " 96 "will be truncated to \"%s\".\n", str, (char *)&cleanedString); 97 } else { 98 memcpy(cleanedString, str.c_str(), str.length()); 99 memset(cleanedString + str.length(), 0, length - str.length()); 100 } 101 proxy.writeBlob(addr, &cleanedString, length); 102 103 uint8_t checkSum = 0; 104 for (int i = 0; i < length; i++) 105 checkSum += cleanedString[i]; 106 107 return checkSum; 108} 109 110Addr 111X86ISA::IntelMP::FloatingPointer::writeOut(PortProxy& proxy, Addr addr) 112{ 113 // Make sure that either a config table is present or a default 114 // configuration was found but not both. 115 if (!tableAddr && !defaultConfig) 116 fatal("Either an MP configuration table or a default configuration " 117 "must be used."); 118 if (tableAddr && defaultConfig) 119 fatal("Both an MP configuration table and a default configuration " 120 "were set."); 121 122 uint8_t checkSum = 0; 123 124 proxy.writeBlob(addr, signature, 4); 125 for (int i = 0; i < 4; i++) 126 checkSum += signature[i]; 127 128 checkSum += writeOutField(proxy, addr + 4, tableAddr); 129 130 // The length of the structure in paragraphs, aka 16 byte chunks. 131 uint8_t length = 1; 132 proxy.writeBlob(addr + 8, &length, 1); 133 checkSum += length; 134 135 proxy.writeBlob(addr + 9, &specRev, 1); 136 checkSum += specRev; 137 138 proxy.writeBlob(addr + 11, &defaultConfig, 1); 139 checkSum += defaultConfig; 140 141 uint32_t features2_5 = imcrPresent ? (1 << 7) : 0; 142 checkSum += writeOutField(proxy, addr + 12, features2_5); 143 144 checkSum = -checkSum; 145 proxy.writeBlob(addr + 10, &checkSum, 1); 146 147 return 16; 148} 149 150X86ISA::IntelMP::FloatingPointer::FloatingPointer(Params * p) : 151 SimObject(p), tableAddr(0), specRev(p->spec_rev), 152 defaultConfig(p->default_config), imcrPresent(p->imcr_present) 153{} 154 155X86ISA::IntelMP::FloatingPointer * 156X86IntelMPFloatingPointerParams::create() 157{ 158 return new X86ISA::IntelMP::FloatingPointer(this); 159} 160 161Addr 162X86ISA::IntelMP::BaseConfigEntry::writeOut(PortProxy& proxy, 163 Addr addr, uint8_t &checkSum) 164{ 165 proxy.writeBlob(addr, &type, 1); 166 checkSum += type; 167 return 1; 168} 169 170X86ISA::IntelMP::BaseConfigEntry::BaseConfigEntry(Params * p, uint8_t _type) : 171 SimObject(p), type(_type) 172{} 173 174Addr 175X86ISA::IntelMP::ExtConfigEntry::writeOut(PortProxy& proxy, 176 Addr addr, uint8_t &checkSum) 177{ 178 proxy.writeBlob(addr, &type, 1); 179 checkSum += type; 180 proxy.writeBlob(addr + 1, &length, 1); 181 checkSum += length; 182 return 1; 183} 184 185X86ISA::IntelMP::ExtConfigEntry::ExtConfigEntry(Params * p, 186 uint8_t _type, uint8_t _length) : 187 SimObject(p), type(_type), length(_length) 188{} 189 190const char X86ISA::IntelMP::ConfigTable::signature[] = "PCMP"; 191 192Addr 193X86ISA::IntelMP::ConfigTable::writeOut(PortProxy& proxy, Addr addr) 194{ 195 uint8_t checkSum = 0; 196 197 proxy.writeBlob(addr, signature, 4); 198 for (int i = 0; i < 4; i++) 199 checkSum += signature[i]; 200 201 // Base table length goes here but will be calculated later. 202 203 proxy.writeBlob(addr + 6, &specRev, 1); 204 checkSum += specRev; 205 206 // The checksum goes here but is still being calculated. 207 208 checkSum += writeOutString(proxy, addr + 8, oemID, 8); 209 checkSum += writeOutString(proxy, addr + 16, productID, 12); 210 211 checkSum += writeOutField(proxy, addr + 28, oemTableAddr); 212 checkSum += writeOutField(proxy, addr + 32, oemTableSize); 213 checkSum += writeOutField(proxy, addr + 34, (uint16_t)baseEntries.size()); 214 checkSum += writeOutField(proxy, addr + 36, localApic); 215 216 uint8_t reserved = 0; 217 proxy.writeBlob(addr + 43, &reserved, 1); 218 checkSum += reserved; 219 220 vector<BaseConfigEntry *>::iterator baseEnt; 221 uint16_t offset = 44; 222 for (baseEnt = baseEntries.begin(); 223 baseEnt != baseEntries.end(); baseEnt++) { 224 offset += (*baseEnt)->writeOut(proxy, addr + offset, checkSum); 225 } 226 227 // We've found the end of the base table this point. 228 checkSum += writeOutField(proxy, addr + 4, offset); 229 230 vector<ExtConfigEntry *>::iterator extEnt; 231 uint16_t extOffset = 0; 232 uint8_t extCheckSum = 0; 233 for (extEnt = extEntries.begin(); 234 extEnt != extEntries.end(); extEnt++) { 235 extOffset += (*extEnt)->writeOut(proxy, 236 addr + offset + extOffset, extCheckSum); 237 } 238 239 checkSum += writeOutField(proxy, addr + 40, extOffset); 240 extCheckSum = -extCheckSum; 241 checkSum += writeOutField(proxy, addr + 42, extCheckSum); 242 243 // And now, we finally have the whole check sum completed. 244 checkSum = -checkSum; 245 writeOutField(proxy, addr + 7, checkSum); 246 247 return offset + extOffset; 248}; 249 250X86ISA::IntelMP::ConfigTable::ConfigTable(Params * p) : SimObject(p), 251 specRev(p->spec_rev), oemID(p->oem_id), productID(p->product_id), 252 oemTableAddr(p->oem_table_addr), oemTableSize(p->oem_table_size), 253 localApic(p->local_apic), 254 baseEntries(p->base_entries), extEntries(p->ext_entries) 255{} 256 257X86ISA::IntelMP::ConfigTable * 258X86IntelMPConfigTableParams::create() 259{ 260 return new X86ISA::IntelMP::ConfigTable(this); 261} 262 263Addr 264X86ISA::IntelMP::Processor::writeOut( 265 PortProxy& proxy, Addr addr, uint8_t &checkSum) 266{ 267 BaseConfigEntry::writeOut(proxy, addr, checkSum); 268 checkSum += writeOutField(proxy, addr + 1, localApicID); 269 checkSum += writeOutField(proxy, addr + 2, localApicVersion); 270 checkSum += writeOutField(proxy, addr + 3, cpuFlags); 271 checkSum += writeOutField(proxy, addr + 4, cpuSignature); 272 checkSum += writeOutField(proxy, addr + 8, featureFlags); 273 274 uint32_t reserved = 0; 275 proxy.writeBlob(addr + 12, &reserved, 4); 276 proxy.writeBlob(addr + 16, &reserved, 4); 277 return 20; 278} 279 280X86ISA::IntelMP::Processor::Processor(Params * p) : BaseConfigEntry(p, 0), 281 localApicID(p->local_apic_id), localApicVersion(p->local_apic_version), 282 cpuFlags(0), cpuSignature(0), featureFlags(p->feature_flags) 283{ 284 if (p->enable) 285 cpuFlags |= (1 << 0); 286 if (p->bootstrap) 287 cpuFlags |= (1 << 1); 288 289 replaceBits(cpuSignature, 0, 3, p->stepping); 290 replaceBits(cpuSignature, 4, 7, p->model); 291 replaceBits(cpuSignature, 8, 11, p->family); 292} 293 294X86ISA::IntelMP::Processor * 295X86IntelMPProcessorParams::create() 296{ 297 return new X86ISA::IntelMP::Processor(this); 298} 299 300Addr 301X86ISA::IntelMP::Bus::writeOut( 302 PortProxy& proxy, Addr addr, uint8_t &checkSum) 303{ 304 BaseConfigEntry::writeOut(proxy, addr, checkSum); 305 checkSum += writeOutField(proxy, addr + 1, busID); 306 checkSum += writeOutString(proxy, addr + 2, busType, 6); 307 return 8; 308} 309 310X86ISA::IntelMP::Bus::Bus(Params * p) : BaseConfigEntry(p, 1), 311 busID(p->bus_id), busType(p->bus_type) 312{} 313 314X86ISA::IntelMP::Bus * 315X86IntelMPBusParams::create() 316{ 317 return new X86ISA::IntelMP::Bus(this); 318} 319 320Addr 321X86ISA::IntelMP::IOAPIC::writeOut( 322 PortProxy& proxy, Addr addr, uint8_t &checkSum) 323{ 324 BaseConfigEntry::writeOut(proxy, addr, checkSum); 325 checkSum += writeOutField(proxy, addr + 1, id); 326 checkSum += writeOutField(proxy, addr + 2, version); 327 checkSum += writeOutField(proxy, addr + 3, flags); 328 checkSum += writeOutField(proxy, addr + 4, address); 329 return 8; 330} 331 332X86ISA::IntelMP::IOAPIC::IOAPIC(Params * p) : BaseConfigEntry(p, 2), 333 id(p->id), version(p->version), flags(0), address(p->address) 334{ 335 if (p->enable) 336 flags |= 1; 337} 338 339X86ISA::IntelMP::IOAPIC * 340X86IntelMPIOAPICParams::create() 341{ 342 return new X86ISA::IntelMP::IOAPIC(this); 343} 344 345Addr 346X86ISA::IntelMP::IntAssignment::writeOut( 347 PortProxy& proxy, Addr addr, uint8_t &checkSum) 348{ 349 BaseConfigEntry::writeOut(proxy, addr, checkSum); 350 checkSum += writeOutField(proxy, addr + 1, interruptType); 351 checkSum += writeOutField(proxy, addr + 2, flags); 352 checkSum += writeOutField(proxy, addr + 4, sourceBusID); 353 checkSum += writeOutField(proxy, addr + 5, sourceBusIRQ); 354 checkSum += writeOutField(proxy, addr + 6, destApicID); 355 checkSum += writeOutField(proxy, addr + 7, destApicIntIn); 356 return 8; 357} 358 359X86ISA::IntelMP::IOIntAssignment::IOIntAssignment(Params * p) : 360 IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 3, 361 p->source_bus_id, p->source_bus_irq, 362 p->dest_io_apic_id, p->dest_io_apic_intin) 363{} 364 365X86ISA::IntelMP::IOIntAssignment * 366X86IntelMPIOIntAssignmentParams::create() 367{ 368 return new X86ISA::IntelMP::IOIntAssignment(this); 369} 370 371X86ISA::IntelMP::LocalIntAssignment::LocalIntAssignment(Params * p) : 372 IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 4, 373 p->source_bus_id, p->source_bus_irq, 374 p->dest_local_apic_id, p->dest_local_apic_intin) 375{} 376 377X86ISA::IntelMP::LocalIntAssignment * 378X86IntelMPLocalIntAssignmentParams::create() 379{ 380 return new X86ISA::IntelMP::LocalIntAssignment(this); 381} 382 383Addr 384X86ISA::IntelMP::AddrSpaceMapping::writeOut( 385 PortProxy& proxy, Addr addr, uint8_t &checkSum) 386{ 387 ExtConfigEntry::writeOut(proxy, addr, checkSum); 388 checkSum += writeOutField(proxy, addr + 2, busID); 389 checkSum += writeOutField(proxy, addr + 3, addrType); 390 checkSum += writeOutField(proxy, addr + 4, addr); 391 checkSum += writeOutField(proxy, addr + 12, addrLength); 392 return length; 393} 394 395X86ISA::IntelMP::AddrSpaceMapping::AddrSpaceMapping(Params * p) : 396 ExtConfigEntry(p, 128, 20), 397 busID(p->bus_id), addrType(p->address_type), 398 addr(p->address), addrLength(p->length) 399{} 400 401X86ISA::IntelMP::AddrSpaceMapping * 402X86IntelMPAddrSpaceMappingParams::create() 403{ 404 return new X86ISA::IntelMP::AddrSpaceMapping(this); 405} 406 407Addr 408X86ISA::IntelMP::BusHierarchy::writeOut( 409 PortProxy& proxy, Addr addr, uint8_t &checkSum) 410{ 411 ExtConfigEntry::writeOut(proxy, addr, checkSum); 412 checkSum += writeOutField(proxy, addr + 2, busID); 413 checkSum += writeOutField(proxy, addr + 3, info); 414 checkSum += writeOutField(proxy, addr + 4, parentBus); 415 416 uint32_t reserved = 0; 417 proxy.writeBlob(addr + 5, &reserved, 3); 418 419 return length; 420} 421 422X86ISA::IntelMP::BusHierarchy::BusHierarchy(Params * p) : 423 ExtConfigEntry(p, 129, 8), 424 busID(p->bus_id), info(0), parentBus(p->parent_bus) 425{ 426 if (p->subtractive_decode) 427 info |= 1; 428} 429 430X86ISA::IntelMP::BusHierarchy * 431X86IntelMPBusHierarchyParams::create() 432{ 433 return new X86ISA::IntelMP::BusHierarchy(this); 434} 435 436Addr 437X86ISA::IntelMP::CompatAddrSpaceMod::writeOut( 438 PortProxy& proxy, Addr addr, uint8_t &checkSum) 439{ 440 ExtConfigEntry::writeOut(proxy, addr, checkSum); 441 checkSum += writeOutField(proxy, addr + 2, busID); 442 checkSum += writeOutField(proxy, addr + 3, mod); 443 checkSum += writeOutField(proxy, addr + 4, rangeList); 444 return length; 445} 446 447X86ISA::IntelMP::CompatAddrSpaceMod::CompatAddrSpaceMod(Params * p) : 448 ExtConfigEntry(p, 130, 8), 449 busID(p->bus_id), mod(0), rangeList(p->range_list) 450{ 451 if (p->add) 452 mod |= 1; 453} 454 455X86ISA::IntelMP::CompatAddrSpaceMod * 456X86IntelMPCompatAddrSpaceModParams::create() 457{ 458 return new X86ISA::IntelMP::CompatAddrSpaceMod(this); 459} 460