system.cc revision 6712
13536SN/A/* 210595Sgabeblack@google.com * Copyright (c) 2007 The Hewlett-Packard Development Company 310037SARM gem5 Developers * All rights reserved. 47752SWilliam.Wang@arm.com * 57752SWilliam.Wang@arm.com * Redistribution and use of this software in source and binary forms, 67752SWilliam.Wang@arm.com * with or without modification, are permitted provided that the 77752SWilliam.Wang@arm.com * following conditions are met: 87752SWilliam.Wang@arm.com * 97752SWilliam.Wang@arm.com * The software must be used only for Non-Commercial Use which means any 107752SWilliam.Wang@arm.com * use which is NOT directed to receiving any direct monetary 117752SWilliam.Wang@arm.com * compensation for, or commercial advantage from such use. Illustrative 127752SWilliam.Wang@arm.com * examples of non-commercial use are academic research, personal study, 137752SWilliam.Wang@arm.com * teaching, education and corporate research & development. 147752SWilliam.Wang@arm.com * Illustrative examples of commercial use are distributing products for 153536SN/A * commercial advantage and providing services using the software for 163536SN/A * commercial advantage. 173536SN/A * 183536SN/A * If you wish to use this software or functionality therein that may be 193536SN/A * covered by patents for commercial use, please contact: 203536SN/A * Director of Intellectual Property Licensing 213536SN/A * Office of Strategy and Technology 223536SN/A * Hewlett-Packard Company 233536SN/A * 1501 Page Mill Road 243536SN/A * Palo Alto, California 94304 253536SN/A * 263536SN/A * Redistributions of source code must retain the above copyright notice, 273536SN/A * this list of conditions and the following disclaimer. Redistributions 283536SN/A * in binary form must reproduce the above copyright notice, this list of 293536SN/A * conditions and the following disclaimer in the documentation and/or 303536SN/A * other materials provided with the distribution. Neither the name of 313536SN/A * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its 323536SN/A * contributors may be used to endorse or promote products derived from 333536SN/A * this software without specific prior written permission. No right of 343536SN/A * sublicense is granted herewith. Derivatives of the software and 353536SN/A * output created using the software may be prepared, but only for 363536SN/A * Non-Commercial Uses. Derivatives of the software may be shared with 373536SN/A * others provided: (i) the others agree to abide by the list of 383536SN/A * conditions herein which includes the Non-Commercial Use restrictions; 393536SN/A * and (ii) such Derivatives of the software include the above copyright 403536SN/A * notice to acknowledge the contribution from this software where 413536SN/A * applicable, this list of conditions and the disclaimer below. 427752SWilliam.Wang@arm.com * 433536SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 443536SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 453536SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 468332Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 478332Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 483536SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 493536SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 503536SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 513536SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 523536SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 533536SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 543536SN/A * 555543SN/A * Authors: Gabe Black 565543SN/A */ 573536SN/A 583536SN/A#include "arch/x86/bios/smbios.hh" 593536SN/A#include "arch/x86/bios/intelmp.hh" 603536SN/A#include "arch/x86/miscregs.hh" 613536SN/A#include "arch/x86/system.hh" 623536SN/A#include "arch/vtophys.hh" 633536SN/A#include "base/intmath.hh" 643536SN/A#include "base/loader/object_file.hh" 653536SN/A#include "base/loader/symtab.hh" 663536SN/A#include "base/remote_gdb.hh" 673536SN/A#include "base/trace.hh" 685543SN/A#include "cpu/thread_context.hh" 695543SN/A#include "mem/physical.hh" 703536SN/A#include "params/X86System.hh" 713536SN/A#include "sim/byteswap.hh" 723536SN/A 733536SN/A 743536SN/Ausing namespace LittleEndianGuest; 753536SN/Ausing namespace X86ISA; 763536SN/A 773536SN/AX86System::X86System(Params *p) : 783536SN/A System(p), smbiosTable(p->smbios_table), 793536SN/A mpFloatingPointer(p->intel_mp_pointer), 803536SN/A mpConfigTable(p->intel_mp_table), 813536SN/A rsdp(p->acpi_description_table_pointer) 823536SN/A{} 833536SN/A 843536SN/Astatic void 853536SN/AinstallSegDesc(ThreadContext *tc, SegmentRegIndex seg, 865543SN/A SegDescriptor desc, bool longmode) 873536SN/A{ 883536SN/A uint64_t base = desc.baseLow + (desc.baseHigh << 24); 893536SN/A bool honorBase = !longmode || seg == SEGMENT_REG_FS || 903536SN/A seg == SEGMENT_REG_GS || 913536SN/A seg == SEGMENT_REG_TSL || 923536SN/A seg == SYS_SEGMENT_REG_TR; 933536SN/A uint64_t limit = desc.limitLow | (desc.limitHigh << 16); 943536SN/A 953536SN/A SegAttr attr = 0; 963536SN/A 973536SN/A attr.dpl = desc.dpl; 983536SN/A attr.unusable = 0; 993536SN/A attr.defaultSize = desc.d; 1003536SN/A attr.longMode = desc.l; 1013536SN/A attr.avl = desc.avl; 1023536SN/A attr.granularity = desc.g; 1033536SN/A attr.present = desc.p; 1043536SN/A attr.system = desc.s; 1053536SN/A attr.type = desc.type; 1065543SN/A if (desc.s) { 1075543SN/A if (desc.type.codeOrData) { 1083536SN/A // Code segment 1093536SN/A attr.expandDown = 0; 1103536SN/A attr.readable = desc.type.r; 1113536SN/A attr.writable = 0; 1123536SN/A } else { 1133536SN/A // Data segment 1143536SN/A attr.expandDown = desc.type.e; 1153536SN/A attr.readable = 1; 1163536SN/A attr.writable = desc.type.w; 1173536SN/A } 1183536SN/A } else { 1193536SN/A attr.readable = 1; 1203536SN/A attr.writable = 1; 1213536SN/A attr.expandDown = 0; 1223536SN/A } 1233536SN/A 1243536SN/A tc->setMiscReg(MISCREG_SEG_BASE(seg), base); 1253536SN/A tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? base : 0); 1263536SN/A tc->setMiscReg(MISCREG_SEG_LIMIT(seg), limit); 1273536SN/A tc->setMiscReg(MISCREG_SEG_ATTR(seg), (MiscReg)attr); 1283536SN/A} 1293536SN/A 1303536SN/Avoid 1313536SN/AX86System::startup() 1323536SN/A{ 1333536SN/A System::startup(); 1345569SN/A ThreadContext *tc = threadContexts[0]; 1353536SN/A // This is the boot strap processor (BSP). Initialize it to look like 1363536SN/A // the boot loader has just turned control over to the 64 bit OS. We 1373536SN/A // won't actually set up real mode or legacy protected mode descriptor 1389020Sgblack@eecs.umich.edu // tables because we aren't executing any code that would require 1398229Snate@binkert.org // them. We do, however toggle the control bits in the correct order 1408229Snate@binkert.org // while allowing consistency checks and the underlying mechansims 1418229Snate@binkert.org // just to be safe. 14210037SARM gem5 Developers 1437752SWilliam.Wang@arm.com const int NumPDTs = 4; 1447752SWilliam.Wang@arm.com 14510707SAndreas.Sandberg@ARM.com const Addr PageMapLevel4 = 0x70000; 1463536SN/A const Addr PageDirPtrTable = 0x71000; 1473536SN/A const Addr PageDirTable[NumPDTs] = 1483536SN/A {0x72000, 0x73000, 0x74000, 0x75000}; 1493536SN/A const Addr GDTBase = 0x76000; 1508229Snate@binkert.org 1513536SN/A const int PML4Bits = 9; 1527752SWilliam.Wang@arm.com const int PDPTBits = 9; 1538232Snate@binkert.org const int PDTBits = 9; 1548232Snate@binkert.org 1558229Snate@binkert.org // Get a port to write the page tables and descriptor tables. 1563536SN/A FunctionalPort * physPort = tc->getPhysPort(); 1573536SN/A 1588782Sgblack@eecs.umich.edu /* 1593536SN/A * Set up the gdt. 1603536SN/A */ 1613536SN/A uint8_t numGDTEntries = 0; 1627752SWilliam.Wang@arm.com // Place holder at selector 0 1633536SN/A uint64_t nullDescriptor = 0; 1645569SN/A physPort->writeBlob(GDTBase + numGDTEntries * 8, 16510601Sgabeblack@google.com (uint8_t *)(&nullDescriptor), 8); 1663536SN/A numGDTEntries++; 1673536SN/A 1683536SN/A //64 bit code segment 1695569SN/A SegDescriptor csDesc = 0; 1705569SN/A csDesc.type.codeOrData = 1; 1715569SN/A csDesc.type.c = 0; // Not conforming 1723536SN/A csDesc.type.r = 1; // Readable 1733536SN/A csDesc.dpl = 0; // Privelege level 0 1743536SN/A csDesc.p = 1; // Present 1758782Sgblack@eecs.umich.edu csDesc.l = 1; // 64 bit 17610707SAndreas.Sandberg@ARM.com csDesc.d = 0; // default operand size 17710707SAndreas.Sandberg@ARM.com csDesc.g = 1; // Page granularity 17810707SAndreas.Sandberg@ARM.com csDesc.s = 1; // Not a system segment 17910707SAndreas.Sandberg@ARM.com csDesc.limitHigh = 0xF; 1808782Sgblack@eecs.umich.edu csDesc.limitLow = 0xFF; 18110707SAndreas.Sandberg@ARM.com //Because we're dealing with a pointer and I don't think it's 1828782Sgblack@eecs.umich.edu //guaranteed that there isn't anything in a nonvirtual class between 1838782Sgblack@eecs.umich.edu //it's beginning in memory and it's actual data, we'll use an 1848782Sgblack@eecs.umich.edu //intermediary. 1858782Sgblack@eecs.umich.edu uint64_t csDescVal = csDesc; 1868782Sgblack@eecs.umich.edu physPort->writeBlob(GDTBase + numGDTEntries * 8, 1878782Sgblack@eecs.umich.edu (uint8_t *)(&csDescVal), 8); 1888782Sgblack@eecs.umich.edu 1898782Sgblack@eecs.umich.edu numGDTEntries++; 1903536SN/A 1918782Sgblack@eecs.umich.edu SegSelector cs = 0; 1928782Sgblack@eecs.umich.edu cs.si = numGDTEntries - 1; 1933536SN/A 1943536SN/A tc->setMiscReg(MISCREG_CS, (MiscReg)cs); 1955569SN/A 1965569SN/A //32 bit data segment 1975569SN/A SegDescriptor dsDesc = 0; 1985569SN/A dsDesc.type.codeOrData = 0; 1993536SN/A dsDesc.type.e = 0; // Not expand down 2003536SN/A dsDesc.type.w = 1; // Writable 2013536SN/A dsDesc.dpl = 0; // Privelege level 0 2027752SWilliam.Wang@arm.com dsDesc.p = 1; // Present 2037752SWilliam.Wang@arm.com dsDesc.d = 1; // default operand size 2043579SN/A dsDesc.g = 1; // Page granularity 2053536SN/A dsDesc.s = 1; // Not a system segment 20610037SARM gem5 Developers dsDesc.limitHigh = 0xF; 20710037SARM gem5 Developers dsDesc.limitLow = 0xFF; 20810595Sgabeblack@google.com uint64_t dsDescVal = dsDesc; 20910595Sgabeblack@google.com physPort->writeBlob(GDTBase + numGDTEntries * 8, 21010037SARM gem5 Developers (uint8_t *)(&dsDescVal), 8); 21110595Sgabeblack@google.com 21210037SARM gem5 Developers numGDTEntries++; 21310595Sgabeblack@google.com 21410595Sgabeblack@google.com SegSelector ds = 0; 21510037SARM gem5 Developers ds.si = numGDTEntries - 1; 21610595Sgabeblack@google.com 21710595Sgabeblack@google.com tc->setMiscReg(MISCREG_DS, (MiscReg)ds); 21810595Sgabeblack@google.com tc->setMiscReg(MISCREG_ES, (MiscReg)ds); 21910595Sgabeblack@google.com tc->setMiscReg(MISCREG_FS, (MiscReg)ds); 22010595Sgabeblack@google.com tc->setMiscReg(MISCREG_GS, (MiscReg)ds); 22110595Sgabeblack@google.com tc->setMiscReg(MISCREG_SS, (MiscReg)ds); 22210037SARM gem5 Developers 22310037SARM gem5 Developers tc->setMiscReg(MISCREG_TSL, 0); 22410037SARM gem5 Developers tc->setMiscReg(MISCREG_TSG_BASE, GDTBase); 22510595Sgabeblack@google.com tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1); 22610595Sgabeblack@google.com 22710595Sgabeblack@google.com SegDescriptor tssDesc = 0; 22810595Sgabeblack@google.com tssDesc.type = 0xB; 22910595Sgabeblack@google.com tssDesc.dpl = 0; // Privelege level 0 23010595Sgabeblack@google.com tssDesc.p = 1; // Present 23110595Sgabeblack@google.com tssDesc.d = 1; // default operand size 23210595Sgabeblack@google.com tssDesc.g = 1; // Page granularity 23310595Sgabeblack@google.com tssDesc.s = 1; // Not a system segment 23410595Sgabeblack@google.com tssDesc.limitHigh = 0xF; 23510595Sgabeblack@google.com tssDesc.limitLow = 0xFF; 23610595Sgabeblack@google.com uint64_t tssDescVal = tssDesc; 23710595Sgabeblack@google.com physPort->writeBlob(GDTBase + numGDTEntries * 8, 23810595Sgabeblack@google.com (uint8_t *)(&tssDescVal), 8); 23910595Sgabeblack@google.com 24010595Sgabeblack@google.com numGDTEntries++; 2413536SN/A 24210037SARM gem5 Developers SegSelector tss = 0; 24310595Sgabeblack@google.com tss.si = numGDTEntries - 1; 2447752SWilliam.Wang@arm.com 24510037SARM gem5 Developers tc->setMiscReg(MISCREG_TR, (MiscReg)tss); 24610595Sgabeblack@google.com installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true); 24710595Sgabeblack@google.com 24810037SARM gem5 Developers /* 24910037SARM gem5 Developers * Identity map the first 4GB of memory. In order to map this region 25010595Sgabeblack@google.com * of memory in long mode, there needs to be one actual page map level 25110595Sgabeblack@google.com * 4 entry which points to one page directory pointer table which 2523536SN/A * points to 4 different page directory tables which are full of two 2533536SN/A * megabyte pages. All of the other entries in valid tables are set 2543536SN/A * to indicate that they don't pertain to anything valid and will 2555569SN/A * cause a fault if used. 2565569SN/A */ 2575569SN/A 2585569SN/A // Put valid values in all of the various table entries which indicate 2593536SN/A // that those entries don't point to further tables or pages. Then 2603536SN/A // set the values of those entries which are needed. 2613536SN/A 2627752SWilliam.Wang@arm.com // Page Map Level 4 2637752SWilliam.Wang@arm.com 26410037SARM gem5 Developers // read/write, user, not present 26510037SARM gem5 Developers uint64_t pml4e = X86ISA::htog(0x6); 26610595Sgabeblack@google.com for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { 26710595Sgabeblack@google.com physPort->writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); 26810037SARM gem5 Developers } 26910595Sgabeblack@google.com // Point to the only PDPT 27010037SARM gem5 Developers pml4e = X86ISA::htog(0x7 | PageDirPtrTable); 27110595Sgabeblack@google.com physPort->writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); 27210037SARM gem5 Developers 27310595Sgabeblack@google.com // Page Directory Pointer Table 27410595Sgabeblack@google.com 27510595Sgabeblack@google.com // read/write, user, not present 27610595Sgabeblack@google.com uint64_t pdpe = X86ISA::htog(0x6); 27710595Sgabeblack@google.com for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { 27810595Sgabeblack@google.com physPort->writeBlob(PageDirPtrTable + offset, 27910037SARM gem5 Developers (uint8_t *)(&pdpe), 8); 28010037SARM gem5 Developers } 28110037SARM gem5 Developers // Point to the PDTs 28210037SARM gem5 Developers for (int table = 0; table < NumPDTs; table++) { 28310037SARM gem5 Developers pdpe = X86ISA::htog(0x7 | PageDirTable[table]); 28410595Sgabeblack@google.com physPort->writeBlob(PageDirPtrTable + table * 8, 28510595Sgabeblack@google.com (uint8_t *)(&pdpe), 8); 28610595Sgabeblack@google.com } 28710595Sgabeblack@google.com 28810595Sgabeblack@google.com // Page Directory Tables 28910595Sgabeblack@google.com 29010595Sgabeblack@google.com Addr base = 0; 29110595Sgabeblack@google.com const Addr pageSize = 2 << 20; 29210595Sgabeblack@google.com for (int table = 0; table < NumPDTs; table++) { 29310595Sgabeblack@google.com for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { 29410595Sgabeblack@google.com // read/write, user, present, 4MB 29510595Sgabeblack@google.com uint64_t pdte = X86ISA::htog(0x87 | base); 29610595Sgabeblack@google.com physPort->writeBlob(PageDirTable[table] + offset, 29710595Sgabeblack@google.com (uint8_t *)(&pdte), 8); 29810595Sgabeblack@google.com base += pageSize; 29910595Sgabeblack@google.com } 3007752SWilliam.Wang@arm.com } 30110037SARM gem5 Developers 30210595Sgabeblack@google.com /* 3037752SWilliam.Wang@arm.com * Transition from real mode all the way up to Long mode 30410037SARM gem5 Developers */ 30510595Sgabeblack@google.com CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); 30610595Sgabeblack@google.com //Turn off paging. 3077752SWilliam.Wang@arm.com cr0.pg = 0; 30810037SARM gem5 Developers tc->setMiscReg(MISCREG_CR0, cr0); 30910595Sgabeblack@google.com //Turn on protected mode. 3103536SN/A cr0.pe = 1; 3113536SN/A tc->setMiscReg(MISCREG_CR0, cr0); 3123536SN/A 3133536SN/A CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 3143536SN/A //Turn on pae. 3153536SN/A cr4.pae = 1; 3163536SN/A tc->setMiscReg(MISCREG_CR4, cr4); 3177752SWilliam.Wang@arm.com 3183536SN/A //Point to the page tables. 3193536SN/A tc->setMiscReg(MISCREG_CR3, PageMapLevel4); 320 321 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 322 //Enable long mode. 323 efer.lme = 1; 324 tc->setMiscReg(MISCREG_EFER, efer); 325 326 //Start using longmode segments. 327 installSegDesc(tc, SEGMENT_REG_CS, csDesc, true); 328 installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true); 329 installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true); 330 installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true); 331 installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true); 332 installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true); 333 334 //Activate long mode. 335 cr0.pg = 1; 336 tc->setMiscReg(MISCREG_CR0, cr0); 337 338 tc->setPC(tc->getSystemPtr()->kernelEntry); 339 tc->setNextPC(tc->readPC()); 340 341 // We should now be in long mode. Yay! 342 343 Addr ebdaPos = 0xF0000; 344 Addr fixed, table; 345 346 //Write out the SMBios/DMI table 347 writeOutSMBiosTable(ebdaPos, fixed, table); 348 ebdaPos += (fixed + table); 349 ebdaPos = roundUp(ebdaPos, 16); 350 351 //Write out the Intel MP Specification configuration table 352 writeOutMPTable(ebdaPos, fixed, table); 353 ebdaPos += (fixed + table); 354} 355 356void 357X86System::writeOutSMBiosTable(Addr header, 358 Addr &headerSize, Addr &structSize, Addr table) 359{ 360 // Get a port to write the table and header to memory. 361 FunctionalPort * physPort = threadContexts[0]->getPhysPort(); 362 363 // If the table location isn't specified, just put it after the header. 364 // The header size as of the 2.5 SMBios specification is 0x1F bytes 365 if (!table) 366 table = header + 0x1F; 367 smbiosTable->setTableAddr(table); 368 369 smbiosTable->writeOut(physPort, header, headerSize, structSize); 370 371 // Do some bounds checking to make sure we at least didn't step on 372 // ourselves. 373 assert(header > table || header + headerSize <= table); 374 assert(table > header || table + structSize <= header); 375} 376 377void 378X86System::writeOutMPTable(Addr fp, 379 Addr &fpSize, Addr &tableSize, Addr table) 380{ 381 // Get a port to write the table and header to memory. 382 FunctionalPort * physPort = threadContexts[0]->getPhysPort(); 383 384 // If the table location isn't specified and it exists, just put 385 // it after the floating pointer. The fp size as of the 1.4 Intel MP 386 // specification is 0x10 bytes. 387 if (mpConfigTable) { 388 if (!table) 389 table = fp + 0x10; 390 mpFloatingPointer->setTableAddr(table); 391 } 392 393 fpSize = mpFloatingPointer->writeOut(physPort, fp); 394 if (mpConfigTable) 395 tableSize = mpConfigTable->writeOut(physPort, table); 396 else 397 tableSize = 0; 398 399 // Do some bounds checking to make sure we at least didn't step on 400 // ourselves and the fp structure was the size we thought it was. 401 assert(fp > table || fp + fpSize <= table); 402 assert(table > fp || table + tableSize <= fp); 403 assert(fpSize == 0x10); 404} 405 406 407X86System::~X86System() 408{ 409 delete smbiosTable; 410} 411 412void 413X86System::serialize(std::ostream &os) 414{ 415 System::serialize(os); 416} 417 418 419void 420X86System::unserialize(Checkpoint *cp, const std::string §ion) 421{ 422 System::unserialize(cp,section); 423} 424 425X86System * 426X86SystemParams::create() 427{ 428 return new X86System(this); 429} 430