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