system.cc revision 11793
11689SN/A/* 29444SAndreas.Sandberg@ARM.com * Copyright (c) 2007 The Hewlett-Packard Development Company 39444SAndreas.Sandberg@ARM.com * All rights reserved. 49444SAndreas.Sandberg@ARM.com * 59444SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 69444SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 79444SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 89444SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 99444SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 109444SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 119444SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 129444SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 139444SAndreas.Sandberg@ARM.com * 142329SN/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/system.hh" 412831Sksewell@umich.edu 421689SN/A#include "arch/vtophys.hh" 431689SN/A#include "arch/x86/bios/intelmp.hh" 449944Smatt.horsnell@ARM.com#include "arch/x86/bios/smbios.hh" 459944Smatt.horsnell@ARM.com#include "arch/x86/isa_traits.hh" 469944Smatt.horsnell@ARM.com#include "arch/x86/regs/misc.hh" 476221Snate@binkert.org#include "base/intmath.hh" 486221Snate@binkert.org#include "base/loader/object_file.hh" 4913449Sgabeblack@google.com#include "base/loader/symtab.hh" 501717SN/A#include "base/trace.hh" 518232Snate@binkert.org#include "cpu/thread_context.hh" 528232Snate@binkert.org#include "mem/port_proxy.hh" 539954SFaissal.Sleiman@arm.com#include "params/X86System.hh" 541060SN/A#include "sim/byteswap.hh" 556221Snate@binkert.org 562292SN/Ausing namespace LittleEndianGuest; 571061SN/Ausing namespace X86ISA; 589954SFaissal.Sleiman@arm.com 5913562Snikos.nikoleris@arm.comX86System::X86System(Params *p) : 6013562Snikos.nikoleris@arm.com System(p), smbiosTable(p->smbios_table), 619954SFaissal.Sleiman@arm.com mpFloatingPointer(p->intel_mp_pointer), 629954SFaissal.Sleiman@arm.com mpConfigTable(p->intel_mp_table), 631060SN/A rsdp(p->acpi_description_table_pointer) 649954SFaissal.Sleiman@arm.com{ 651060SN/A} 662292SN/A 6713562Snikos.nikoleris@arm.comvoid 682292SN/AX86ISA::installSegDesc(ThreadContext *tc, SegmentRegIndex seg, 696221Snate@binkert.org SegDescriptor desc, bool longmode) 706221Snate@binkert.org{ 712292SN/A uint64_t base = desc.baseLow + (desc.baseHigh << 24); 722292SN/A bool honorBase = !longmode || seg == SEGMENT_REG_FS || 7313562Snikos.nikoleris@arm.com seg == SEGMENT_REG_GS || 744329Sktlim@umich.edu seg == SEGMENT_REG_TSL || 752292SN/A seg == SYS_SEGMENT_REG_TR; 762292SN/A uint64_t limit = desc.limitLow | (desc.limitHigh << 16); 772292SN/A 782292SN/A SegAttr attr = 0; 792292SN/A 806221Snate@binkert.org attr.dpl = desc.dpl; 816221Snate@binkert.org attr.unusable = 0; 822292SN/A attr.defaultSize = desc.d; 832292SN/A attr.longMode = desc.l; 8413562Snikos.nikoleris@arm.com attr.avl = desc.avl; 854329Sktlim@umich.edu attr.granularity = desc.g; 862292SN/A attr.present = desc.p; 879954SFaissal.Sleiman@arm.com attr.system = desc.s; 882292SN/A attr.type = desc.type; 892292SN/A if (desc.s) { 906221Snate@binkert.org if (desc.type.codeOrData) { 916221Snate@binkert.org // Code segment 922292SN/A attr.expandDown = 0; 932292SN/A attr.readable = desc.type.r; 9413562Snikos.nikoleris@arm.com attr.writable = 0; 9513453Srekai.gonzalezalberquilla@arm.com } else { 9613453Srekai.gonzalezalberquilla@arm.com // Data segment 9713453Srekai.gonzalezalberquilla@arm.com attr.expandDown = desc.type.e; 981060SN/A attr.readable = 1; 999444SAndreas.Sandberg@ARM.com attr.writable = desc.type.w; 1009444SAndreas.Sandberg@ARM.com } 1019444SAndreas.Sandberg@ARM.com } else { 1029444SAndreas.Sandberg@ARM.com attr.readable = 1; 1039444SAndreas.Sandberg@ARM.com attr.writable = 1; 1049444SAndreas.Sandberg@ARM.com attr.expandDown = 0; 1059444SAndreas.Sandberg@ARM.com } 10613453Srekai.gonzalezalberquilla@arm.com 1079444SAndreas.Sandberg@ARM.com tc->setMiscReg(MISCREG_SEG_BASE(seg), base); 1086221Snate@binkert.org tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? base : 0); 1099444SAndreas.Sandberg@ARM.com tc->setMiscReg(MISCREG_SEG_LIMIT(seg), limit); 11013453Srekai.gonzalezalberquilla@arm.com tc->setMiscReg(MISCREG_SEG_ATTR(seg), (MiscReg)attr); 1112292SN/A} 1129444SAndreas.Sandberg@ARM.com 1131060SN/Avoid 1142292SN/AX86System::initState() 1152292SN/A{ 1162292SN/A System::initState(); 1172292SN/A 1182292SN/A if (!kernel) 1192292SN/A fatal("No kernel to load.\n"); 1202292SN/A 1214329Sktlim@umich.edu if (kernel->getArch() == ObjectFile::I386) 1224329Sktlim@umich.edu fatal("Loading a 32 bit x86 kernel is not supported.\n"); 1234329Sktlim@umich.edu 1244329Sktlim@umich.edu ThreadContext *tc = threadContexts[0]; 1254329Sktlim@umich.edu // This is the boot strap processor (BSP). Initialize it to look like 1264329Sktlim@umich.edu // the boot loader has just turned control over to the 64 bit OS. We 1274329Sktlim@umich.edu // won't actually set up real mode or legacy protected mode descriptor 1282292SN/A // tables because we aren't executing any code that would require 1296221Snate@binkert.org // them. We do, however toggle the control bits in the correct order 1302292SN/A // while allowing consistency checks and the underlying mechansims 1312292SN/A // just to be safe. 1322292SN/A 1332292SN/A const int NumPDTs = 4; 1342292SN/A 1352307SN/A const Addr PageMapLevel4 = 0x70000; 1362307SN/A const Addr PageDirPtrTable = 0x71000; 1379444SAndreas.Sandberg@ARM.com const Addr PageDirTable[NumPDTs] = 1382307SN/A {0x72000, 0x73000, 0x74000, 0x75000}; 1399444SAndreas.Sandberg@ARM.com const Addr GDTBase = 0x76000; 1409444SAndreas.Sandberg@ARM.com 1419444SAndreas.Sandberg@ARM.com const int PML4Bits = 9; 1422307SN/A const int PDPTBits = 9; 1432307SN/A const int PDTBits = 9; 1442307SN/A 1452307SN/A /* 1462307SN/A * Set up the gdt. 1472307SN/A */ 1489444SAndreas.Sandberg@ARM.com uint8_t numGDTEntries = 0; 1492307SN/A // Place holder at selector 0 1502292SN/A uint64_t nullDescriptor = 0; 1512292SN/A physProxy.writeBlob(GDTBase + numGDTEntries * 8, 1522292SN/A (uint8_t *)(&nullDescriptor), 8); 1532292SN/A numGDTEntries++; 1542292SN/A 15513562Snikos.nikoleris@arm.com SegDescriptor initDesc = 0; 15614016SAndrea.Mondelli@ucf.edu initDesc.type.codeOrData = 0; // code or data type 1572292SN/A initDesc.type.c = 0; // conforming 1586221Snate@binkert.org initDesc.type.r = 1; // readable 1596221Snate@binkert.org initDesc.dpl = 0; // privilege 1602292SN/A initDesc.p = 1; // present 1613867Sbinkertn@umich.edu initDesc.l = 1; // longmode - 64 bit 1626221Snate@binkert.org initDesc.d = 0; // operand size 1633867Sbinkertn@umich.edu initDesc.g = 1; // granularity 16413562Snikos.nikoleris@arm.com initDesc.s = 1; // system segment 1653867Sbinkertn@umich.edu initDesc.limitHigh = 0xFFFF; 16613562Snikos.nikoleris@arm.com initDesc.limitLow = 0xF; 16713562Snikos.nikoleris@arm.com initDesc.baseHigh = 0x0; 1683867Sbinkertn@umich.edu initDesc.baseLow = 0x0; 1692292SN/A 1702292SN/A //64 bit code segment 1712292SN/A SegDescriptor csDesc = initDesc; 1722292SN/A csDesc.type.codeOrData = 1; 1732292SN/A csDesc.dpl = 0; 1742292SN/A //Because we're dealing with a pointer and I don't think it's 1752292SN/A //guaranteed that there isn't anything in a nonvirtual class between 1766221Snate@binkert.org //it's beginning in memory and it's actual data, we'll use an 1772292SN/A //intermediary. 17813562Snikos.nikoleris@arm.com uint64_t csDescVal = csDesc; 1792292SN/A physProxy.writeBlob(GDTBase + numGDTEntries * 8, 1802292SN/A (uint8_t *)(&csDescVal), 8); 1812292SN/A 1822292SN/A numGDTEntries++; 1831060SN/A 1841060SN/A SegSelector cs = 0; 1851061SN/A cs.si = numGDTEntries - 1; 1861060SN/A 1871060SN/A tc->setMiscReg(MISCREG_CS, (MiscReg)cs); 1881060SN/A 1896221Snate@binkert.org //32 bit data segment 1901061SN/A SegDescriptor dsDesc = initDesc; 1916221Snate@binkert.org uint64_t dsDescVal = dsDesc; 1926221Snate@binkert.org physProxy.writeBlob(GDTBase + numGDTEntries * 8, 1931060SN/A (uint8_t *)(&dsDescVal), 8); 1942292SN/A 1952292SN/A numGDTEntries++; 1961060SN/A 1972292SN/A SegSelector ds = 0; 19814016SAndrea.Mondelli@ucf.edu ds.si = numGDTEntries - 1; 1996221Snate@binkert.org 2002292SN/A tc->setMiscReg(MISCREG_DS, (MiscReg)ds); 2012292SN/A tc->setMiscReg(MISCREG_ES, (MiscReg)ds); 2021060SN/A tc->setMiscReg(MISCREG_FS, (MiscReg)ds); 2031060SN/A tc->setMiscReg(MISCREG_GS, (MiscReg)ds); 2041061SN/A tc->setMiscReg(MISCREG_SS, (MiscReg)ds); 2051060SN/A 20613429Srekai.gonzalezalberquilla@arm.com tc->setMiscReg(MISCREG_TSL, 0); 2071060SN/A tc->setMiscReg(MISCREG_TSG_BASE, GDTBase); 2081060SN/A tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1); 2091060SN/A 2107897Shestness@cs.utexas.edu SegDescriptor tssDesc = initDesc; 2117897Shestness@cs.utexas.edu uint64_t tssDescVal = tssDesc; 2127720Sgblack@eecs.umich.edu physProxy.writeBlob(GDTBase + numGDTEntries * 8, 2131060SN/A (uint8_t *)(&tssDescVal), 8); 2141060SN/A 2151060SN/A numGDTEntries++; 2166221Snate@binkert.org 2171060SN/A SegSelector tss = 0; 2182292SN/A tss.si = numGDTEntries - 1; 2192292SN/A 2202292SN/A tc->setMiscReg(MISCREG_TR, (MiscReg)tss); 2212292SN/A installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true); 2222292SN/A 2232292SN/A /* 2241060SN/A * Identity map the first 4GB of memory. In order to map this region 2251060SN/A * of memory in long mode, there needs to be one actual page map level 2262292SN/A * 4 entry which points to one page directory pointer table which 2272292SN/A * points to 4 different page directory tables which are full of two 2282292SN/A * megabyte pages. All of the other entries in valid tables are set 2292292SN/A * to indicate that they don't pertain to anything valid and will 2302292SN/A * cause a fault if used. 2312292SN/A */ 2322292SN/A 2332292SN/A // Put valid values in all of the various table entries which indicate 2342292SN/A // that those entries don't point to further tables or pages. Then 2352292SN/A // set the values of those entries which are needed. 2361060SN/A 2371060SN/A // Page Map Level 4 2382292SN/A 2391060SN/A // read/write, user, not present 2401060SN/A uint64_t pml4e = X86ISA::htog(0x6); 2412292SN/A for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { 2422292SN/A physProxy.writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); 2436221Snate@binkert.org } 2442292SN/A // Point to the only PDPT 2457897Shestness@cs.utexas.edu pml4e = X86ISA::htog(0x7 | PageDirPtrTable); 2467897Shestness@cs.utexas.edu physProxy.writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); 2471061SN/A 2481060SN/A // Page Directory Pointer Table 24913429Srekai.gonzalezalberquilla@arm.com 2502292SN/A // read/write, user, not present 2511060SN/A uint64_t pdpe = X86ISA::htog(0x6); 25213429Srekai.gonzalezalberquilla@arm.com for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { 25313429Srekai.gonzalezalberquilla@arm.com physProxy.writeBlob(PageDirPtrTable + offset, 2541858SN/A (uint8_t *)(&pdpe), 8); 2551060SN/A } 2561060SN/A // Point to the PDTs 25713831SAndrea.Mondelli@ucf.edu for (int table = 0; table < NumPDTs; table++) { 25813831SAndrea.Mondelli@ucf.edu pdpe = X86ISA::htog(0x7 | PageDirTable[table]); 2591060SN/A physProxy.writeBlob(PageDirPtrTable + table * 8, 2601060SN/A (uint8_t *)(&pdpe), 8); 2611060SN/A } 2622292SN/A 2631060SN/A // Page Directory Tables 2642731Sktlim@umich.edu 2652292SN/A Addr base = 0; 2662292SN/A const Addr pageSize = 2 << 20; 2672292SN/A for (int table = 0; table < NumPDTs; table++) { 2682292SN/A for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { 2692292SN/A // read/write, user, present, 4MB 2702329SN/A uint64_t pdte = X86ISA::htog(0x87 | base); 2712329SN/A physProxy.writeBlob(PageDirTable[table] + offset, 2722329SN/A (uint8_t *)(&pdte), 8); 2731681SN/A base += pageSize; 2741060SN/A } 2752292SN/A } 2762292SN/A 2772292SN/A /* 2786221Snate@binkert.org * Transition from real mode all the way up to Long mode 2792292SN/A */ 2807897Shestness@cs.utexas.edu CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); 2812292SN/A //Turn off paging. 2822292SN/A cr0.pg = 0; 2832292SN/A tc->setMiscReg(MISCREG_CR0, cr0); 2842292SN/A //Turn on protected mode. 2852292SN/A cr0.pe = 1; 2862292SN/A tc->setMiscReg(MISCREG_CR0, cr0); 2872292SN/A 2882292SN/A CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 2892292SN/A //Turn on pae. 2902292SN/A cr4.pae = 1; 2912292SN/A tc->setMiscReg(MISCREG_CR4, cr4); 2922292SN/A 2936221Snate@binkert.org //Point to the page tables. 2946221Snate@binkert.org tc->setMiscReg(MISCREG_CR3, PageMapLevel4); 2952292SN/A 2963867Sbinkertn@umich.edu Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 2976221Snate@binkert.org //Enable long mode. 2982292SN/A efer.lme = 1; 2992292SN/A tc->setMiscReg(MISCREG_EFER, efer); 3002292SN/A 3012292SN/A //Start using longmode segments. 3021060SN/A installSegDesc(tc, SEGMENT_REG_CS, csDesc, true); 3031060SN/A installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true); 3041060SN/A installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true); 3051060SN/A installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true); 3061060SN/A installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true); 3071061SN/A installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true); 3081060SN/A 3091060SN/A //Activate long mode. 3101060SN/A cr0.pg = 1; 3111060SN/A tc->setMiscReg(MISCREG_CR0, cr0); 3121060SN/A 3131060SN/A tc->pcState(tc->getSystemPtr()->kernelEntry); 3141061SN/A 3152292SN/A // We should now be in long mode. Yay! 3166221Snate@binkert.org 3171060SN/A Addr ebdaPos = 0xF0000; 3182292SN/A Addr fixed, table; 3191060SN/A 3201060SN/A //Write out the SMBios/DMI table 3211061SN/A writeOutSMBiosTable(ebdaPos, fixed, table); 3221060SN/A ebdaPos += (fixed + table); 3236221Snate@binkert.org ebdaPos = roundUp(ebdaPos, 16); 3241060SN/A 3257897Shestness@cs.utexas.edu //Write out the Intel MP Specification configuration table 32613831SAndrea.Mondelli@ucf.edu writeOutMPTable(ebdaPos, fixed, table); 3272877Sksewell@umich.edu ebdaPos += (fixed + table); 3281858SN/A} 3292292SN/A 3302292SN/Avoid 3312877Sksewell@umich.eduX86System::writeOutSMBiosTable(Addr header, 33213831SAndrea.Mondelli@ucf.edu Addr &headerSize, Addr &structSize, Addr table) 3332292SN/A{ 3342292SN/A // If the table location isn't specified, just put it after the header. 3352292SN/A // The header size as of the 2.5 SMBios specification is 0x1F bytes 3362292SN/A if (!table) 3372292SN/A table = header + 0x1F; 3382292SN/A smbiosTable->setTableAddr(table); 3392292SN/A 3402292SN/A smbiosTable->writeOut(physProxy, header, headerSize, structSize); 3412292SN/A 3421858SN/A // Do some bounds checking to make sure we at least didn't step on 3431858SN/A // ourselves. 3442292SN/A assert(header > table || header + headerSize <= table); 3452292SN/A assert(table > header || table + structSize <= header); 3462877Sksewell@umich.edu} 3471858SN/A 3481858SN/Avoid 34913831SAndrea.Mondelli@ucf.eduX86System::writeOutMPTable(Addr fp, 3502292SN/A Addr &fpSize, Addr &tableSize, Addr table) 3517720Sgblack@eecs.umich.edu{ 3522292SN/A // If the table location isn't specified and it exists, just put 3531858SN/A // it after the floating pointer. The fp size as of the 1.4 Intel MP 3541858SN/A // specification is 0x10 bytes. 3551858SN/A if (mpConfigTable) { 3562292SN/A if (!table) 3571858SN/A table = fp + 0x10; 3582292SN/A mpFloatingPointer->setTableAddr(table); 3591858SN/A } 3602292SN/A 3612292SN/A fpSize = mpFloatingPointer->writeOut(physProxy, fp); 3622292SN/A if (mpConfigTable) 3631858SN/A tableSize = mpConfigTable->writeOut(physProxy, table); 3641858SN/A else 3652292SN/A tableSize = 0; 3661858SN/A 3672292SN/A // Do some bounds checking to make sure we at least didn't step on 3681858SN/A // ourselves and the fp structure was the size we thought it was. 3691858SN/A assert(fp > table || fp + fpSize <= table); 3701858SN/A assert(table > fp || table + tableSize <= fp); 3711858SN/A assert(fpSize == 0x10); 3722292SN/A} 3732292SN/A 3742292SN/A 3752292SN/AX86System::~X86System() 3762292SN/A{ 3772292SN/A delete smbiosTable; 3782292SN/A} 3791858SN/A 3801858SN/AX86System * 3811858SN/AX86SystemParams::create() 3821858SN/A{ 3832877Sksewell@umich.edu return new X86System(this); 38413831SAndrea.Mondelli@ucf.edu} 3852292SN/A