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 &section)
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