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