system.cc revision 13613:a19963be12ca
13116SN/A/*
23116SN/A * Copyright (c) 2007 The Hewlett-Packard Development Company
33116SN/A * Copyright (c) 2018 TU Dresden
43116SN/A * All rights reserved.
53116SN/A *
63116SN/A * The license below extends only to copyright in the software and shall
73116SN/A * not be construed as granting a license to any other intellectual
83116SN/A * property including but not limited to intellectual property relating
93116SN/A * to a hardware implementation of the functionality of the software
103116SN/A * licensed hereunder.  You may use the software subject to the license
113116SN/A * terms below provided that you ensure that this notice is replicated
123116SN/A * unmodified and in its entirety in all distributions of the software,
133116SN/A * modified or unmodified, in source code or in binary form.
143116SN/A *
153116SN/A * Redistribution and use in source and binary forms, with or without
163116SN/A * modification, are permitted provided that the following conditions are
173116SN/A * met: redistributions of source code must retain the above copyright
183116SN/A * notice, this list of conditions and the following disclaimer;
193116SN/A * redistributions in binary form must reproduce the above copyright
203116SN/A * notice, this list of conditions and the following disclaimer in the
213116SN/A * documentation and/or other materials provided with the distribution;
223116SN/A * neither the name of the copyright holders nor the names of its
233116SN/A * contributors may be used to endorse or promote products derived from
243116SN/A * this software without specific prior written permission.
253116SN/A *
263116SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
273116SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
283116SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
293116SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
303116SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
313116SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
323116SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
333318SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
343318SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
353318SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
363116SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
373116SN/A *
3811263Sandreas.sandberg@arm.com * Authors: Gabe Black
394263SN/A *          Maximilian Stein
404263SN/A */
414263SN/A
424263SN/A#include "arch/x86/system.hh"
434263SN/A
444762SN/A#include "arch/x86/bios/intelmp.hh"
4510469SN/A#include "arch/x86/bios/smbios.hh"
464762SN/A#include "arch/x86/isa_traits.hh"
473116SN/A#include "base/loader/object_file.hh"
484263SN/A#include "cpu/thread_context.hh"
499152SN/A#include "params/X86System.hh"
508232SN/A
513116SN/Ausing namespace LittleEndianGuest;
523405SN/Ausing namespace X86ISA;
534762SN/A
543116SN/AX86System::X86System(Params *p) :
553116SN/A    System(p), smbiosTable(p->smbios_table),
563116SN/A    mpFloatingPointer(p->intel_mp_pointer),
573318SN/A    mpConfigTable(p->intel_mp_table),
584263SN/A    rsdp(p->acpi_description_table_pointer)
593318SN/A{
604981SN/A}
6110913SN/A
6212064Sgabeblack@google.comvoid
6312064Sgabeblack@google.comX86ISA::installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
6412064Sgabeblack@google.com        SegDescriptor desc, bool longmode)
6511320Ssteve.reinhardt@amd.com{
6611320Ssteve.reinhardt@amd.com    bool honorBase = !longmode || seg == SEGMENT_REG_FS ||
675535SN/A                                  seg == SEGMENT_REG_GS ||
684291SN/A                                  seg == SEGMENT_REG_TSL ||
694283SN/A                                  seg == SYS_SEGMENT_REG_TR;
705500SN/A
719157SN/A    SegAttr attr = 0;
723116SN/A
734981SN/A    attr.dpl = desc.dpl;
744981SN/A    attr.unusable = 0;
753318SN/A    attr.defaultSize = desc.d;
764263SN/A    attr.longMode = desc.l;
774218SN/A    attr.avl = desc.avl;
784218SN/A    attr.granularity = desc.g;
794218SN/A    attr.present = desc.p;
804218SN/A    attr.system = desc.s;
814218SN/A    attr.type = desc.type;
824218SN/A    if (desc.s) {
834283SN/A        if (desc.type.codeOrData) {
844218SN/A            // Code segment
854218SN/A            attr.expandDown = 0;
864263SN/A            attr.readable = desc.type.r;
874263SN/A            attr.writable = 0;
884263SN/A        } else {
894263SN/A            // Data segment
904218SN/A            attr.expandDown = desc.type.e;
915763SN/A            attr.readable = 1;
925763SN/A            attr.writable = desc.type.w;
935763SN/A        }
943116SN/A    } else {
954218SN/A        attr.readable = 1;
964218SN/A        attr.writable = 1;
973405SN/A        attr.expandDown = 0;
983318SN/A    }
993318SN/A
1003318SN/A    tc->setMiscReg(MISCREG_SEG_BASE(seg), desc.base);
1013318SN/A    tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? desc.base : 0);
1023318SN/A    tc->setMiscReg(MISCREG_SEG_LIMIT(seg), desc.limit);
1033405SN/A    tc->setMiscReg(MISCREG_SEG_ATTR(seg), (RegVal)attr);
1043405SN/A}
1053405SN/A
1064283SN/Avoid
1074283SN/AX86System::initState()
1084283SN/A{
1094283SN/A    System::initState();
1104218SN/A
1114218SN/A    if (!kernel)
1124218SN/A        fatal("No kernel to load.\n");
1134283SN/A
1144283SN/A    if (kernel->getArch() == ObjectFile::I386)
1154218SN/A        fatal("Loading a 32 bit x86 kernel is not supported.\n");
1163318SN/A
1174218SN/A    ThreadContext *tc = threadContexts[0];
1184263SN/A    // This is the boot strap processor (BSP). Initialize it to look like
1195954SN/A    // the boot loader has just turned control over to the 64 bit OS. We
1205954SN/A    // won't actually set up real mode or legacy protected mode descriptor
1215954SN/A    // tables because we aren't executing any code that would require
1224263SN/A    // them. We do, however toggle the control bits in the correct order
1234263SN/A    // while allowing consistency checks and the underlying mechansims
1243116SN/A    // just to be safe.
1253116SN/A
1269086SN/A    const int NumPDTs = 4;
1279086SN/A
1289086SN/A    const Addr PageMapLevel4 = 0x70000;
1299086SN/A    const Addr PageDirPtrTable = 0x71000;
1309086SN/A    const Addr PageDirTable[NumPDTs] =
1315954SN/A        {0x72000, 0x73000, 0x74000, 0x75000};
1325954SN/A    const Addr GDTBase = 0x76000;
1335954SN/A
1345954SN/A    const int PML4Bits = 9;
1359807SN/A    const int PDPTBits = 9;
1365954SN/A    const int PDTBits = 9;
1375954SN/A
1384981SN/A    /*
1394981SN/A     * Set up the gdt.
1404981SN/A     */
1414981SN/A    uint8_t numGDTEntries = 0;
1424987SN/A    // Place holder at selector 0
1434981SN/A    uint64_t nullDescriptor = 0;
1444981SN/A    physProxy.writeBlob(GDTBase + numGDTEntries * 8,
1454981SN/A                        (uint8_t *)(&nullDescriptor), 8);
1464981SN/A    numGDTEntries++;
1474981SN/A
1484981SN/A    SegDescriptor initDesc = 0;
1493116SN/A    initDesc.type.codeOrData = 0; // code or data type
1503116SN/A    initDesc.type.c = 0;          // conforming
1513349SN/A    initDesc.type.r = 1;          // readable
1523116SN/A    initDesc.dpl = 0;             // privilege
1533116SN/A    initDesc.p = 1;               // present
1543116SN/A    initDesc.l = 1;               // longmode - 64 bit
1559807SN/A    initDesc.d = 0;               // operand size
1563116SN/A    initDesc.g = 1;               // granularity
1573116SN/A    initDesc.s = 1;               // system segment
1583116SN/A    initDesc.limit = 0xFFFFFFFF;
1596124SN/A    initDesc.base = 0;
1606124SN/A
1616124SN/A    // 64 bit code segment
1623116SN/A    SegDescriptor csDesc = initDesc;
1639198SN/A    csDesc.type.codeOrData = 1;
1643116SN/A    csDesc.dpl = 0;
1653116SN/A    // Because we're dealing with a pointer and I don't think it's
1666124SN/A    // guaranteed that there isn't anything in a nonvirtual class between
1676124SN/A    // it's beginning in memory and it's actual data, we'll use an
1686124SN/A    // intermediary.
1693116SN/A    uint64_t csDescVal = csDesc;
1703349SN/A    physProxy.writeBlob(GDTBase + numGDTEntries * 8,
1713116SN/A                        (uint8_t *)(&csDescVal), 8);
1723116SN/A
1733116SN/A    numGDTEntries++;
1743116SN/A
1753116SN/A    SegSelector cs = 0;
1763116SN/A    cs.si = numGDTEntries - 1;
1773116SN/A
1783116SN/A    tc->setMiscReg(MISCREG_CS, (RegVal)cs);
1793116SN/A
1803116SN/A    // 32 bit data segment
1813318SN/A    SegDescriptor dsDesc = initDesc;
1823318SN/A    uint64_t dsDescVal = dsDesc;
1833318SN/A    physProxy.writeBlob(GDTBase + numGDTEntries * 8,
1844283SN/A                        (uint8_t *)(&dsDescVal), 8);
1853116SN/A
1866124SN/A    numGDTEntries++;
1876124SN/A
1886124SN/A    SegSelector ds = 0;
1893116SN/A    ds.si = numGDTEntries - 1;
1903405SN/A
1913318SN/A    tc->setMiscReg(MISCREG_DS, (RegVal)ds);
1924218SN/A    tc->setMiscReg(MISCREG_ES, (RegVal)ds);
1934218SN/A    tc->setMiscReg(MISCREG_FS, (RegVal)ds);
1944218SN/A    tc->setMiscReg(MISCREG_GS, (RegVal)ds);
1954218SN/A    tc->setMiscReg(MISCREG_SS, (RegVal)ds);
1964218SN/A
1974218SN/A    tc->setMiscReg(MISCREG_TSL, 0);
1984218SN/A    tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
1994218SN/A    tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
2004218SN/A
2014218SN/A    SegDescriptor tssDesc = initDesc;
2024218SN/A    uint64_t tssDescVal = tssDesc;
2034218SN/A    physProxy.writeBlob(GDTBase + numGDTEntries * 8,
2044218SN/A                        (uint8_t *)(&tssDescVal), 8);
2054218SN/A
2064218SN/A    numGDTEntries++;
2074218SN/A
2084218SN/A    SegSelector tss = 0;
2094218SN/A    tss.si = numGDTEntries - 1;
2104218SN/A
2116124SN/A    tc->setMiscReg(MISCREG_TR, (RegVal)tss);
2126124SN/A    installSegDesc(tc, SYS_SEGMENT_REG_TR, tssDesc, true);
2134218SN/A
2144283SN/A    /*
2154283SN/A     * Identity map the first 4GB of memory. In order to map this region
2164283SN/A     * of memory in long mode, there needs to be one actual page map level
2174263SN/A     * 4 entry which points to one page directory pointer table which
2184283SN/A     * points to 4 different page directory tables which are full of two
2194283SN/A     * megabyte pages. All of the other entries in valid tables are set
2204283SN/A     * to indicate that they don't pertain to anything valid and will
2214218SN/A     * cause a fault if used.
2225763SN/A     */
2235763SN/A
2245763SN/A    // Put valid values in all of the various table entries which indicate
2255763SN/A    // that those entries don't point to further tables or pages. Then
2265763SN/A    // set the values of those entries which are needed.
2274218SN/A
2284218SN/A    // Page Map Level 4
2294218SN/A
2304218SN/A    // read/write, user, not present
2314218SN/A    uint64_t pml4e = X86ISA::htog(0x6);
2324218SN/A    for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) {
2334218SN/A        physProxy.writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8);
2344218SN/A    }
2354218SN/A    // Point to the only PDPT
2364218SN/A    pml4e = X86ISA::htog(0x7 | PageDirPtrTable);
2374218SN/A    physProxy.writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8);
2384218SN/A
2394218SN/A    // Page Directory Pointer Table
2404218SN/A
2414218SN/A    // read/write, user, not present
2424218SN/A    uint64_t pdpe = X86ISA::htog(0x6);
24311810Sbaz21@cam.ac.uk    for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) {
24411810Sbaz21@cam.ac.uk        physProxy.writeBlob(PageDirPtrTable + offset,
2454218SN/A                            (uint8_t *)(&pdpe), 8);
2464218SN/A    }
2474218SN/A    // Point to the PDTs
2484218SN/A    for (int table = 0; table < NumPDTs; table++) {
2494218SN/A        pdpe = X86ISA::htog(0x7 | PageDirTable[table]);
2504218SN/A        physProxy.writeBlob(PageDirPtrTable + table * 8,
2514218SN/A                            (uint8_t *)(&pdpe), 8);
2524218SN/A    }
2534218SN/A
2544218SN/A    // Page Directory Tables
2554218SN/A
2564218SN/A    Addr base = 0;
2574218SN/A    const Addr pageSize = 2 << 20;
2584218SN/A    for (int table = 0; table < NumPDTs; table++) {
2594218SN/A        for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) {
2604218SN/A            // read/write, user, present, 4MB
2614218SN/A            uint64_t pdte = X86ISA::htog(0x87 | base);
2624218SN/A            physProxy.writeBlob(PageDirTable[table] + offset,
2635763SN/A                                (uint8_t *)(&pdte), 8);
2645763SN/A            base += pageSize;
2655763SN/A        }
2664218SN/A    }
2674218SN/A
2684218SN/A    /*
2694218SN/A     * Transition from real mode all the way up to Long mode
2704218SN/A     */
2714218SN/A    CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
2724218SN/A    // Turn off paging.
2734218SN/A    cr0.pg = 0;
2744263SN/A    tc->setMiscReg(MISCREG_CR0, cr0);
2754263SN/A    // Turn on protected mode.
2766124SN/A    cr0.pe = 1;
2776124SN/A    tc->setMiscReg(MISCREG_CR0, cr0);
2784263SN/A
2794263SN/A    CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
2804263SN/A    // Turn on pae.
2814218SN/A    cr4.pae = 1;
2825763SN/A    tc->setMiscReg(MISCREG_CR4, cr4);
2835763SN/A
2845763SN/A    // Point to the page tables.
2854218SN/A    tc->setMiscReg(MISCREG_CR3, PageMapLevel4);
2864218SN/A
2874218SN/A    Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
2884218SN/A    // Enable long mode.
2894218SN/A    efer.lme = 1;
2904218SN/A    tc->setMiscReg(MISCREG_EFER, efer);
2914218SN/A
2924218SN/A    // Start using longmode segments.
2934218SN/A    installSegDesc(tc, SEGMENT_REG_CS, csDesc, true);
2944218SN/A    installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true);
2954218SN/A    installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true);
2964218SN/A    installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true);
2974218SN/A    installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true);
2984218SN/A    installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true);
2994218SN/A
3005763SN/A    // Activate long mode.
3015763SN/A    cr0.pg = 1;
3025763SN/A    tc->setMiscReg(MISCREG_CR0, cr0);
3034218SN/A
3044218SN/A    tc->pcState(tc->getSystemPtr()->kernelEntry);
3054218SN/A
3064218SN/A    // We should now be in long mode. Yay!
3074218SN/A
3084218SN/A    Addr ebdaPos = 0xF0000;
3094218SN/A    Addr fixed, table;
3104218SN/A
3114218SN/A    // Write out the SMBios/DMI table.
3124218SN/A    writeOutSMBiosTable(ebdaPos, fixed, table);
3134218SN/A    ebdaPos += (fixed + table);
3144218SN/A    ebdaPos = roundUp(ebdaPos, 16);
3155763SN/A
3165763SN/A    // Write out the Intel MP Specification configuration table.
3175763SN/A    writeOutMPTable(ebdaPos, fixed, table);
3185763SN/A    ebdaPos += (fixed + table);
3195763SN/A}
3205763SN/A
3214218SN/Avoid
3224218SN/AX86System::writeOutSMBiosTable(Addr header,
3234218SN/A        Addr &headerSize, Addr &structSize, Addr table)
3245763SN/A{
3255763SN/A    // If the table location isn't specified, just put it after the header.
3265763SN/A    // The header size as of the 2.5 SMBios specification is 0x1F bytes.
3275763SN/A    if (!table)
3285763SN/A        table = header + 0x1F;
3295763SN/A    smbiosTable->setTableAddr(table);
3304218SN/A
3314218SN/A    smbiosTable->writeOut(physProxy, header, headerSize, structSize);
3324218SN/A
3335763SN/A    // Do some bounds checking to make sure we at least didn't step on
3345763SN/A    // ourselves.
3355763SN/A    assert(header > table || header + headerSize <= table);
3365763SN/A    assert(table > header || table + structSize <= header);
3375763SN/A}
3385763SN/A
3395763SN/Avoid
3405763SN/AX86System::writeOutMPTable(Addr fp,
3415763SN/A        Addr &fpSize, Addr &tableSize, Addr table)
3425763SN/A{
3433318SN/A    // If the table location isn't specified and it exists, just put
3446124SN/A    // it after the floating pointer. The fp size as of the 1.4 Intel MP
3456124SN/A    // specification is 0x10 bytes.
3466124SN/A    if (mpConfigTable) {
3476124SN/A        if (!table)
3484218SN/A            table = fp + 0x10;
3494218SN/A        mpFloatingPointer->setTableAddr(table);
3504218SN/A    }
3513318SN/A
3523318SN/A    fpSize = mpFloatingPointer->writeOut(physProxy, fp);
3534870SN/A    if (mpConfigTable)
3543116SN/A        tableSize = mpConfigTable->writeOut(physProxy, table);
3553116SN/A    else
3563116SN/A        tableSize = 0;
3573116SN/A
3583349SN/A    // Do some bounds checking to make sure we at least didn't step on
3593116SN/A    // ourselves and the fp structure was the size we thought it was.
3603116SN/A    assert(fp > table || fp + fpSize <= table);
3613116SN/A    assert(table > fp || table + tableSize <= fp);
3623116SN/A    assert(fpSize == 0x10);
3633318SN/A}
3643116SN/A
3653116SN/A
3663116SN/AX86System::~X86System()
3673116SN/A{
3683116SN/A    delete smbiosTable;
3693116SN/A}
3703318SN/A
3713318SN/AX86System *
3723318SN/AX86SystemParams::create()
3736124SN/A{
3746124SN/A    return new X86System(this);
3753116SN/A}
3766124SN/A