system.cc revision 7720
11689SN/A/* 27598Sminkyu.jeong@arm.com * Copyright (c) 2007 The Hewlett-Packard Development Company 37598Sminkyu.jeong@arm.com * All rights reserved. 47598Sminkyu.jeong@arm.com * 57598Sminkyu.jeong@arm.com * The license below extends only to copyright in the software and shall 67598Sminkyu.jeong@arm.com * not be construed as granting a license to any other intellectual 77598Sminkyu.jeong@arm.com * property including but not limited to intellectual property relating 87598Sminkyu.jeong@arm.com * to a hardware implementation of the functionality of the software 97598Sminkyu.jeong@arm.com * licensed hereunder. You may use the software subject to the license 107598Sminkyu.jeong@arm.com * terms below provided that you ensure that this notice is replicated 117598Sminkyu.jeong@arm.com * unmodified and in its entirety in all distributions of the software, 127598Sminkyu.jeong@arm.com * modified or unmodified, in source code or in binary form. 137598Sminkyu.jeong@arm.com * 142326SN/A * Redistribution and use in source and binary forms, with or without 151689SN/A * modification, are permitted provided that the following conditions are 161689SN/A * met: redistributions of source code must retain the above copyright 171689SN/A * notice, this list of conditions and the following disclaimer; 181689SN/A * redistributions in binary form must reproduce the above copyright 191689SN/A * notice, this list of conditions and the following disclaimer in the 201689SN/A * documentation and/or other materials provided with the distribution; 211689SN/A * neither the name of the copyright holders nor the names of its 221689SN/A * contributors may be used to endorse or promote products derived from 231689SN/A * this software without specific prior written permission. 241689SN/A * 251689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 261689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 271689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 281689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 291689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 301689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 311689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 351689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361689SN/A * 371689SN/A * Authors: Gabe Black 381689SN/A */ 392665Ssaidi@eecs.umich.edu 402665Ssaidi@eecs.umich.edu#include "arch/x86/bios/smbios.hh" 411689SN/A#include "arch/x86/bios/intelmp.hh" 421689SN/A#include "arch/x86/regs/misc.hh" 431060SN/A#include "arch/x86/system.hh" 441060SN/A#include "arch/vtophys.hh" 451689SN/A#include "base/intmath.hh" 461060SN/A#include "base/loader/object_file.hh" 471060SN/A#include "base/loader/symtab.hh" 481060SN/A#include "base/trace.hh" 498230Snate@binkert.org#include "cpu/thread_context.hh" 506658Snate@binkert.org#include "mem/physical.hh" 512292SN/A#include "params/X86System.hh" 521717SN/A#include "sim/byteswap.hh" 538229Snate@binkert.org 548232Snate@binkert.org 558232Snate@binkert.orgusing namespace LittleEndianGuest; 568232Snate@binkert.orgusing namespace X86ISA; 575529Snate@binkert.org 581060SN/AX86System::X86System(Params *p) : 596221Snate@binkert.org System(p), smbiosTable(p->smbios_table), 606221Snate@binkert.org mpFloatingPointer(p->intel_mp_pointer), 611681SN/A mpConfigTable(p->intel_mp_table), 625529Snate@binkert.org rsdp(p->acpi_description_table_pointer) 632873Sktlim@umich.edu{ 644329Sktlim@umich.edu if (kernel->getArch() == ObjectFile::I386) 654329Sktlim@umich.edu fatal("Loading a 32 bit x86 kernel is not supported.\n"); 664329Sktlim@umich.edu} 672292SN/A 682292SN/Astatic void 692292SN/AinstallSegDesc(ThreadContext *tc, SegmentRegIndex seg, 702292SN/A SegDescriptor desc, bool longmode) 712820Sktlim@umich.edu{ 722292SN/A uint64_t base = desc.baseLow + (desc.baseHigh << 24); 732820Sktlim@umich.edu bool honorBase = !longmode || seg == SEGMENT_REG_FS || 742820Sktlim@umich.edu seg == SEGMENT_REG_GS || 755529Snate@binkert.org seg == SEGMENT_REG_TSL || 762307SN/A seg == SYS_SEGMENT_REG_TR; 771060SN/A uint64_t limit = desc.limitLow | (desc.limitHigh << 16); 782292SN/A 792292SN/A SegAttr attr = 0; 802292SN/A 811060SN/A attr.dpl = desc.dpl; 821060SN/A attr.unusable = 0; 831060SN/A attr.defaultSize = desc.d; 841060SN/A attr.longMode = desc.l; 851060SN/A attr.avl = desc.avl; 861060SN/A attr.granularity = desc.g; 871681SN/A attr.present = desc.p; 886221Snate@binkert.org attr.system = desc.s; 896221Snate@binkert.org attr.type = desc.type; 906221Snate@binkert.org if (desc.s) { 916221Snate@binkert.org if (desc.type.codeOrData) { 922292SN/A // Code segment 932292SN/A attr.expandDown = 0; 942820Sktlim@umich.edu attr.readable = desc.type.r; 952820Sktlim@umich.edu attr.writable = 0; 962292SN/A } else { 972292SN/A // Data segment 982820Sktlim@umich.edu attr.expandDown = desc.type.e; 992820Sktlim@umich.edu attr.readable = 1; 1002292SN/A attr.writable = desc.type.w; 1012292SN/A } 1022292SN/A } else { 1032292SN/A attr.readable = 1; 1042292SN/A attr.writable = 1; 1052292SN/A attr.expandDown = 0; 1062292SN/A } 1072292SN/A 1081060SN/A tc->setMiscReg(MISCREG_SEG_BASE(seg), base); 1091060SN/A tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? base : 0); 1101681SN/A tc->setMiscReg(MISCREG_SEG_LIMIT(seg), limit); 1111062SN/A tc->setMiscReg(MISCREG_SEG_ATTR(seg), (MiscReg)attr); 1122292SN/A} 1131062SN/A 1142301SN/Avoid 1152301SN/AX86System::initState() 1161062SN/A{ 1172727Sktlim@umich.edu System::initState(); 1181062SN/A 1191062SN/A ThreadContext *tc = threadContexts[0]; 1201062SN/A // This is the boot strap processor (BSP). Initialize it to look like 1211062SN/A // the boot loader has just turned control over to the 64 bit OS. We 1221062SN/A // won't actually set up real mode or legacy protected mode descriptor 1231062SN/A // tables because we aren't executing any code that would require 1241062SN/A // them. We do, however toggle the control bits in the correct order 1251062SN/A // while allowing consistency checks and the underlying mechansims 1261062SN/A // just to be safe. 1271062SN/A 1281062SN/A const int NumPDTs = 4; 1291062SN/A 1301062SN/A const Addr PageMapLevel4 = 0x70000; 1311062SN/A const Addr PageDirPtrTable = 0x71000; 1321062SN/A const Addr PageDirTable[NumPDTs] = 1331062SN/A {0x72000, 0x73000, 0x74000, 0x75000}; 1341062SN/A const Addr GDTBase = 0x76000; 1351062SN/A 1361062SN/A const int PML4Bits = 9; 1371062SN/A const int PDPTBits = 9; 1381062SN/A const int PDTBits = 9; 1391062SN/A 1401062SN/A // Get a port to write the page tables and descriptor tables. 1411062SN/A FunctionalPort * physPort = tc->getPhysPort(); 1421062SN/A 1431062SN/A /* 1441062SN/A * Set up the gdt. 1451062SN/A */ 1461062SN/A uint8_t numGDTEntries = 0; 1471062SN/A // Place holder at selector 0 1481062SN/A uint64_t nullDescriptor = 0; 1491062SN/A physPort->writeBlob(GDTBase + numGDTEntries * 8, 1501062SN/A (uint8_t *)(&nullDescriptor), 8); 1511062SN/A numGDTEntries++; 1521062SN/A 1531062SN/A //64 bit code segment 1541062SN/A SegDescriptor csDesc = 0; 1551062SN/A csDesc.type.codeOrData = 1; 1561062SN/A csDesc.type.c = 0; // Not conforming 1571062SN/A csDesc.type.r = 1; // Readable 1581062SN/A csDesc.dpl = 0; // Privelege level 0 1592292SN/A csDesc.p = 1; // Present 1602292SN/A csDesc.l = 1; // 64 bit 1612292SN/A csDesc.d = 0; // default operand size 1622292SN/A csDesc.g = 1; // Page granularity 1631062SN/A csDesc.s = 1; // Not a system segment 1641062SN/A csDesc.limitHigh = 0xF; 1651062SN/A csDesc.limitLow = 0xFF; 1661062SN/A //Because we're dealing with a pointer and I don't think it's 1671062SN/A //guaranteed that there isn't anything in a nonvirtual class between 1681062SN/A //it's beginning in memory and it's actual data, we'll use an 1691062SN/A //intermediary. 1702292SN/A uint64_t csDescVal = csDesc; 1712292SN/A physPort->writeBlob(GDTBase + numGDTEntries * 8, 1722292SN/A (uint8_t *)(&csDescVal), 8); 1732292SN/A 1742292SN/A numGDTEntries++; 1752292SN/A 1762292SN/A SegSelector cs = 0; 1772292SN/A cs.si = numGDTEntries - 1; 1782292SN/A 1792292SN/A tc->setMiscReg(MISCREG_CS, (MiscReg)cs); 1802301SN/A 1812727Sktlim@umich.edu //32 bit data segment 1822353SN/A SegDescriptor dsDesc = 0; 1832727Sktlim@umich.edu dsDesc.type.codeOrData = 0; 1842727Sktlim@umich.edu dsDesc.type.e = 0; // Not expand down 1852727Sktlim@umich.edu dsDesc.type.w = 1; // Writable 1866221Snate@binkert.org dsDesc.dpl = 0; // Privelege level 0 1872353SN/A dsDesc.p = 1; // Present 1882727Sktlim@umich.edu dsDesc.d = 1; // default operand size 1892727Sktlim@umich.edu dsDesc.g = 1; // Page granularity 1902727Sktlim@umich.edu dsDesc.s = 1; // Not a system segment 1912727Sktlim@umich.edu dsDesc.limitHigh = 0xF; 1922353SN/A dsDesc.limitLow = 0xFF; 1932727Sktlim@umich.edu uint64_t dsDescVal = dsDesc; 1942727Sktlim@umich.edu physPort->writeBlob(GDTBase + numGDTEntries * 8, 1952727Sktlim@umich.edu (uint8_t *)(&dsDescVal), 8); 1966221Snate@binkert.org 1978240Snate@binkert.org numGDTEntries++; 1982301SN/A 1992727Sktlim@umich.edu SegSelector ds = 0; 2002301SN/A ds.si = numGDTEntries - 1; 2012727Sktlim@umich.edu 2026221Snate@binkert.org tc->setMiscReg(MISCREG_DS, (MiscReg)ds); 2038240Snate@binkert.org tc->setMiscReg(MISCREG_ES, (MiscReg)ds); 2042301SN/A tc->setMiscReg(MISCREG_FS, (MiscReg)ds); 2052727Sktlim@umich.edu tc->setMiscReg(MISCREG_GS, (MiscReg)ds); 2062301SN/A tc->setMiscReg(MISCREG_SS, (MiscReg)ds); 2072727Sktlim@umich.edu 2086221Snate@binkert.org tc->setMiscReg(MISCREG_TSL, 0); 2098240Snate@binkert.org tc->setMiscReg(MISCREG_TSG_BASE, GDTBase); 2102301SN/A tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1); 2112727Sktlim@umich.edu 2122301SN/A SegDescriptor tssDesc = 0; 2132727Sktlim@umich.edu tssDesc.type = 0xB; 2146221Snate@binkert.org tssDesc.dpl = 0; // Privelege level 0 2158240Snate@binkert.org tssDesc.p = 1; // Present 2162301SN/A tssDesc.d = 1; // default operand size 2172727Sktlim@umich.edu tssDesc.g = 1; // Page granularity 2182301SN/A tssDesc.s = 1; // Not a system segment 2192301SN/A tssDesc.limitHigh = 0xF; 2208240Snate@binkert.org tssDesc.limitLow = 0xFF; 2212301SN/A uint64_t tssDescVal = tssDesc; 2222727Sktlim@umich.edu physPort->writeBlob(GDTBase + numGDTEntries * 8, 2232727Sktlim@umich.edu (uint8_t *)(&tssDescVal), 8); 2242727Sktlim@umich.edu 2252727Sktlim@umich.edu numGDTEntries++; 2268240Snate@binkert.org 2272727Sktlim@umich.edu SegSelector tss = 0; 2282727Sktlim@umich.edu tss.si = numGDTEntries - 1; 2292727Sktlim@umich.edu 2302727Sktlim@umich.edu tc->setMiscReg(MISCREG_TR, (MiscReg)tss); 2312301SN/A installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true); 2322301SN/A 2336221Snate@binkert.org /* 2348240Snate@binkert.org * Identity map the first 4GB of memory. In order to map this region 2352301SN/A * of memory in long mode, there needs to be one actual page map level 2362727Sktlim@umich.edu * 4 entry which points to one page directory pointer table which 2372301SN/A * points to 4 different page directory tables which are full of two 2382326SN/A * megabyte pages. All of the other entries in valid tables are set 2396221Snate@binkert.org * to indicate that they don't pertain to anything valid and will 2408240Snate@binkert.org * cause a fault if used. 2412301SN/A */ 2422727Sktlim@umich.edu 2432301SN/A // Put valid values in all of the various table entries which indicate 2442326SN/A // that those entries don't point to further tables or pages. Then 2456221Snate@binkert.org // set the values of those entries which are needed. 2468240Snate@binkert.org 2472301SN/A // Page Map Level 4 2482727Sktlim@umich.edu 2492301SN/A // read/write, user, not present 2502326SN/A uint64_t pml4e = X86ISA::htog(0x6); 2516221Snate@binkert.org for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { 2528240Snate@binkert.org physPort->writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); 2532301SN/A } 2542727Sktlim@umich.edu // Point to the only PDPT 2552301SN/A pml4e = X86ISA::htog(0x7 | PageDirPtrTable); 2562326SN/A physPort->writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); 2576221Snate@binkert.org 2588240Snate@binkert.org // Page Directory Pointer Table 2592301SN/A 2602727Sktlim@umich.edu // read/write, user, not present 2612301SN/A uint64_t pdpe = X86ISA::htog(0x6); 2622326SN/A for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { 2638240Snate@binkert.org physPort->writeBlob(PageDirPtrTable + offset, 2642301SN/A (uint8_t *)(&pdpe), 8); 2652727Sktlim@umich.edu } 2662301SN/A // Point to the PDTs 2672326SN/A for (int table = 0; table < NumPDTs; table++) { 2682301SN/A pdpe = X86ISA::htog(0x7 | PageDirTable[table]); 2692326SN/A physPort->writeBlob(PageDirPtrTable + table * 8, 2708240Snate@binkert.org (uint8_t *)(&pdpe), 8); 2712301SN/A } 2722727Sktlim@umich.edu 2732301SN/A // Page Directory Tables 2742326SN/A 2752301SN/A Addr base = 0; 2762326SN/A const Addr pageSize = 2 << 20; 2778240Snate@binkert.org for (int table = 0; table < NumPDTs; table++) { 2782301SN/A for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { 2792727Sktlim@umich.edu // read/write, user, present, 4MB 2802326SN/A uint64_t pdte = X86ISA::htog(0x87 | base); 2811062SN/A physPort->writeBlob(PageDirTable[table] + offset, 2821062SN/A (uint8_t *)(&pdte), 8); 2831681SN/A base += pageSize; 2841060SN/A } 2852292SN/A } 2861060SN/A 2876221Snate@binkert.org /* 2882292SN/A * Transition from real mode all the way up to Long mode 2892292SN/A */ 2902292SN/A CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); 2912292SN/A //Turn off paging. 2922292SN/A cr0.pg = 0; 2932292SN/A tc->setMiscReg(MISCREG_CR0, cr0); 2942292SN/A //Turn on protected mode. 2952292SN/A cr0.pe = 1; 2962292SN/A tc->setMiscReg(MISCREG_CR0, cr0); 2972733Sktlim@umich.edu 2981060SN/A CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 2991060SN/A //Turn on pae. 3001681SN/A cr4.pae = 1; 3011060SN/A tc->setMiscReg(MISCREG_CR4, cr4); 3022292SN/A 3031060SN/A //Point to the page tables. 3041060SN/A tc->setMiscReg(MISCREG_CR3, PageMapLevel4); 3051060SN/A 3061060SN/A Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 3071060SN/A //Enable long mode. 3081060SN/A efer.lme = 1; 3091060SN/A tc->setMiscReg(MISCREG_EFER, efer); 3101060SN/A 3111060SN/A //Start using longmode segments. 3122292SN/A installSegDesc(tc, SEGMENT_REG_CS, csDesc, true); 3132292SN/A installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true); 3141060SN/A installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true); 3151060SN/A installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true); 3161060SN/A installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true); 3171060SN/A installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true); 3181681SN/A 3191060SN/A //Activate long mode. 3202292SN/A cr0.pg = 1; 3211060SN/A tc->setMiscReg(MISCREG_CR0, cr0); 3221060SN/A 3231060SN/A tc->pcState(tc->getSystemPtr()->kernelEntry); 3241060SN/A 3251060SN/A // We should now be in long mode. Yay! 3261060SN/A 3271060SN/A Addr ebdaPos = 0xF0000; 3281681SN/A Addr fixed, table; 3291060SN/A 3302292SN/A //Write out the SMBios/DMI table 3311060SN/A writeOutSMBiosTable(ebdaPos, fixed, table); 3321060SN/A ebdaPos += (fixed + table); 3331060SN/A ebdaPos = roundUp(ebdaPos, 16); 3341060SN/A 3351060SN/A //Write out the Intel MP Specification configuration table 3361060SN/A writeOutMPTable(ebdaPos, fixed, table); 3371060SN/A ebdaPos += (fixed + table); 3381681SN/A} 3391060SN/A 3406221Snate@binkert.orgvoid 3411060SN/AX86System::writeOutSMBiosTable(Addr header, 3422292SN/A Addr &headerSize, Addr &structSize, Addr table) 3432292SN/A{ 3442292SN/A // Get a port to write the table and header to memory. 3452292SN/A FunctionalPort * physPort = threadContexts[0]->getPhysPort(); 3461060SN/A 3471060SN/A // If the table location isn't specified, just put it after the header. 3481681SN/A // The header size as of the 2.5 SMBios specification is 0x1F bytes 3491060SN/A if (!table) 3502292SN/A table = header + 0x1F; 3511060SN/A smbiosTable->setTableAddr(table); 3522292SN/A 3531060SN/A smbiosTable->writeOut(physPort, header, headerSize, structSize); 3541060SN/A 3552307SN/A // Do some bounds checking to make sure we at least didn't step on 3562863Sktlim@umich.edu // ourselves. 3572843Sktlim@umich.edu assert(header > table || header + headerSize <= table); 3582307SN/A assert(table > header || table + structSize <= header); 3592843Sktlim@umich.edu} 3602843Sktlim@umich.edu 3612863Sktlim@umich.eduvoid 3621681SN/AX86System::writeOutMPTable(Addr fp, 3631681SN/A Addr &fpSize, Addr &tableSize, Addr table) 3642316SN/A{ 3651681SN/A // Get a port to write the table and header to memory. 3662843Sktlim@umich.edu FunctionalPort * physPort = threadContexts[0]->getPhysPort(); 3672843Sktlim@umich.edu 3682843Sktlim@umich.edu // If the table location isn't specified and it exists, just put 3692843Sktlim@umich.edu // it after the floating pointer. The fp size as of the 1.4 Intel MP 3702843Sktlim@umich.edu // specification is 0x10 bytes. 3712843Sktlim@umich.edu if (mpConfigTable) { 3722843Sktlim@umich.edu if (!table) 3731681SN/A table = fp + 0x10; 3742348SN/A mpFloatingPointer->setTableAddr(table); 3752307SN/A } 3762367SN/A 3772367SN/A fpSize = mpFloatingPointer->writeOut(physPort, fp); 3781681SN/A if (mpConfigTable) 3792307SN/A tableSize = mpConfigTable->writeOut(physPort, table); 3802307SN/A else 3812307SN/A tableSize = 0; 3822307SN/A 3836221Snate@binkert.org // Do some bounds checking to make sure we at least didn't step on 3846221Snate@binkert.org // ourselves and the fp structure was the size we thought it was. 3856221Snate@binkert.org assert(fp > table || fp + fpSize <= table); 3866221Snate@binkert.org assert(table > fp || table + tableSize <= fp); 3876221Snate@binkert.org assert(fpSize == 0x10); 3882307SN/A} 3891681SN/A 3901681SN/A 3912307SN/AX86System::~X86System() 3921681SN/A{ 3932307SN/A delete smbiosTable; 3941060SN/A} 3952348SN/A 3962307SN/Avoid 3972307SN/AX86System::serialize(std::ostream &os) 3982307SN/A{ 3992307SN/A System::serialize(os); 4001060SN/A} 4012307SN/A 4022307SN/A 4032307SN/Avoid 4041060SN/AX86System::unserialize(Checkpoint *cp, const std::string §ion) 4052307SN/A{ 4062307SN/A System::unserialize(cp,section); 4071060SN/A} 4086221Snate@binkert.org 4096221Snate@binkert.orgX86System * 4106221Snate@binkert.orgX86SystemParams::create() 4116221Snate@binkert.org{ 4122307SN/A return new X86System(this); 4131060SN/A} 4142307SN/A