faults.cc revision 8806
12SN/A/*
210676Sandreas.hansson@arm.com * Copyright (c) 2007 The Hewlett-Packard Development Company
39235Sandreas.hansson@arm.com * All rights reserved.
49235Sandreas.hansson@arm.com *
59235Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
69235Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
79235Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
89235Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
99235Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
109235Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
119235Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
129235Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
139235Sandreas.hansson@arm.com *
141762SN/A * Copyright (c) 2003-2007 The Regents of The University of Michigan
152SN/A * All rights reserved.
162SN/A *
172SN/A * Redistribution and use in source and binary forms, with or without
182SN/A * modification, are permitted provided that the following conditions are
192SN/A * met: redistributions of source code must retain the above copyright
202SN/A * notice, this list of conditions and the following disclaimer;
212SN/A * redistributions in binary form must reproduce the above copyright
222SN/A * notice, this list of conditions and the following disclaimer in the
232SN/A * documentation and/or other materials provided with the distribution;
242SN/A * neither the name of the copyright holders nor the names of its
252SN/A * contributors may be used to endorse or promote products derived from
262SN/A * this software without specific prior written permission.
272SN/A *
282SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Gabe Black
412665SN/A */
429235Sandreas.hansson@arm.com
432SN/A#include "arch/x86/decoder.hh"
442SN/A#include "arch/x86/faults.hh"
459235Sandreas.hansson@arm.com#include "arch/x86/isa_traits.hh"
469235Sandreas.hansson@arm.com#include "base/trace.hh"
472SN/A#include "cpu/thread_context.hh"
4810481Sandreas.hansson@arm.com#include "debug/Faults.hh"
499412Sandreas.hansson@arm.com#include "sim/full_system.hh"
509412Sandreas.hansson@arm.com
519411Sandreas.hansson@arm.comnamespace X86ISA
529405Sandreas.hansson@arm.com{
539411Sandreas.hansson@arm.com    void X86FaultBase::invoke(ThreadContext * tc, StaticInstPtr inst)
549235Sandreas.hansson@arm.com    {
559235Sandreas.hansson@arm.com        if (!FullSystem) {
5610676Sandreas.hansson@arm.com            FaultBase::invoke(tc, inst);
5710676Sandreas.hansson@arm.com            return;
5810676Sandreas.hansson@arm.com        }
5910676Sandreas.hansson@arm.com
6010676Sandreas.hansson@arm.com        PCState pcState = tc->pcState();
6110676Sandreas.hansson@arm.com        Addr pc = pcState.pc();
6210676Sandreas.hansson@arm.com        DPRINTF(Faults, "RIP %#x: vector %d: %s\n",
6310676Sandreas.hansson@arm.com                pc, vector, describe());
6410676Sandreas.hansson@arm.com        using namespace X86ISAInst::RomLabels;
6510676Sandreas.hansson@arm.com        HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
6610676Sandreas.hansson@arm.com        MicroPC entry;
6710676Sandreas.hansson@arm.com        if (m5reg.mode == LongMode) {
6810676Sandreas.hansson@arm.com            if (isSoft()) {
6910676Sandreas.hansson@arm.com                entry = extern_label_longModeSoftInterrupt;
7010676Sandreas.hansson@arm.com            } else {
7110676Sandreas.hansson@arm.com                entry = extern_label_longModeInterrupt;
729235Sandreas.hansson@arm.com            }
732SN/A        } else {
742SN/A            entry = extern_label_legacyModeInterrupt;
759405Sandreas.hansson@arm.com        }
769405Sandreas.hansson@arm.com        tc->setIntReg(INTREG_MICRO(1), vector);
779411Sandreas.hansson@arm.com        tc->setIntReg(INTREG_MICRO(7), pc);
7810435Snilay@cs.wisc.edu        if (errorCode != (uint64_t)(-1)) {
799405Sandreas.hansson@arm.com            if (m5reg.mode == LongMode) {
809405Sandreas.hansson@arm.com                entry = extern_label_longModeInterruptWithError;
819405Sandreas.hansson@arm.com            } else {
829411Sandreas.hansson@arm.com                panic("Legacy mode interrupts with error codes "
839411Sandreas.hansson@arm.com                        "aren't implementde.\n");
849411Sandreas.hansson@arm.com            }
8510676Sandreas.hansson@arm.com            // Software interrupts shouldn't have error codes. If one
8610676Sandreas.hansson@arm.com            // does, there would need to be microcode to set it up.
8710676Sandreas.hansson@arm.com            assert(!isSoft());
8810676Sandreas.hansson@arm.com            tc->setIntReg(INTREG_MICRO(15), errorCode);
899411Sandreas.hansson@arm.com        }
909411Sandreas.hansson@arm.com        pcState.upc(romMicroPC(entry));
919411Sandreas.hansson@arm.com        pcState.nupc(romMicroPC(entry) + 1);
929411Sandreas.hansson@arm.com        tc->pcState(pcState);
939411Sandreas.hansson@arm.com    }
949411Sandreas.hansson@arm.com
959411Sandreas.hansson@arm.com    std::string
969235Sandreas.hansson@arm.com    X86FaultBase::describe() const
972SN/A    {
989235Sandreas.hansson@arm.com        std::stringstream ss;
9910676Sandreas.hansson@arm.com        ccprintf(ss, "%s", mnemonic());
10010676Sandreas.hansson@arm.com        if (errorCode != (uint64_t)(-1)) {
1019411Sandreas.hansson@arm.com            ccprintf(ss, "(%#x)", errorCode);
1029411Sandreas.hansson@arm.com        }
1039411Sandreas.hansson@arm.com
10410676Sandreas.hansson@arm.com        return ss.str();
10510676Sandreas.hansson@arm.com    }
1069411Sandreas.hansson@arm.com
10710676Sandreas.hansson@arm.com    void X86Trap::invoke(ThreadContext * tc, StaticInstPtr inst)
10810676Sandreas.hansson@arm.com    {
10910676Sandreas.hansson@arm.com        X86FaultBase::invoke(tc);
11010676Sandreas.hansson@arm.com        if (!FullSystem)
11110676Sandreas.hansson@arm.com            return;
11210676Sandreas.hansson@arm.com
11310676Sandreas.hansson@arm.com        // This is the same as a fault, but it happens -after- the
11410676Sandreas.hansson@arm.com        // instruction.
11510676Sandreas.hansson@arm.com        PCState pc = tc->pcState();
11610676Sandreas.hansson@arm.com        pc.uEnd();
11710676Sandreas.hansson@arm.com    }
11810676Sandreas.hansson@arm.com
11910676Sandreas.hansson@arm.com    void X86Abort::invoke(ThreadContext * tc, StaticInstPtr inst)
12010676Sandreas.hansson@arm.com    {
12110676Sandreas.hansson@arm.com        panic("Abort exception!");
12210676Sandreas.hansson@arm.com    }
12310676Sandreas.hansson@arm.com
12410676Sandreas.hansson@arm.com    void
12510676Sandreas.hansson@arm.com    InvalidOpcode::invoke(ThreadContext * tc, StaticInstPtr inst)
12610676Sandreas.hansson@arm.com    {
12710676Sandreas.hansson@arm.com        if (FullSystem) {
12810676Sandreas.hansson@arm.com            X86Fault::invoke(tc, inst);
12910676Sandreas.hansson@arm.com        } else {
13010676Sandreas.hansson@arm.com            panic("Unrecognized/invalid instruction executed:\n %s",
1319235Sandreas.hansson@arm.com                    inst->machInst);
1329235Sandreas.hansson@arm.com        }
13310676Sandreas.hansson@arm.com    }
13410676Sandreas.hansson@arm.com
1359235Sandreas.hansson@arm.com    void PageFault::invoke(ThreadContext * tc, StaticInstPtr inst)
1369235Sandreas.hansson@arm.com    {
1379405Sandreas.hansson@arm.com        if (FullSystem) {
1389412Sandreas.hansson@arm.com            HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
1399412Sandreas.hansson@arm.com            X86FaultBase::invoke(tc);
1409412Sandreas.hansson@arm.com            /*
1419412Sandreas.hansson@arm.com             * If something bad happens while trying to enter the page fault
1429412Sandreas.hansson@arm.com             * handler, I'm pretty sure that's a double fault and then all
1439412Sandreas.hansson@arm.com             * bets are off. That means it should be safe to update this
14410676Sandreas.hansson@arm.com             * state now.
14510676Sandreas.hansson@arm.com             */
1469412Sandreas.hansson@arm.com            if (m5reg.mode == LongMode) {
1479412Sandreas.hansson@arm.com                tc->setMiscReg(MISCREG_CR2, addr);
1489412Sandreas.hansson@arm.com            } else {
1499412Sandreas.hansson@arm.com                tc->setMiscReg(MISCREG_CR2, (uint32_t)addr);
1509412Sandreas.hansson@arm.com            }
1519412Sandreas.hansson@arm.com        } else {
15210676Sandreas.hansson@arm.com            PageFaultErrorCode code = errorCode;
1539412Sandreas.hansson@arm.com            const char *modeStr = "";
1549412Sandreas.hansson@arm.com            if (code.fetch)
1559412Sandreas.hansson@arm.com                modeStr = "execute";
1569412Sandreas.hansson@arm.com            else if (code.write)
1579412Sandreas.hansson@arm.com                modeStr = "write";
1589412Sandreas.hansson@arm.com            else
1599412Sandreas.hansson@arm.com                modeStr = "read";
16010676Sandreas.hansson@arm.com            panic("Tried to %s unmapped address %#x.\n", modeStr, addr);
16110676Sandreas.hansson@arm.com        }
1629412Sandreas.hansson@arm.com    }
1639412Sandreas.hansson@arm.com
1649412Sandreas.hansson@arm.com    std::string
16510676Sandreas.hansson@arm.com    PageFault::describe() const
1669412Sandreas.hansson@arm.com    {
16710676Sandreas.hansson@arm.com        std::stringstream ss;
1689412Sandreas.hansson@arm.com        ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr);
1699412Sandreas.hansson@arm.com        return ss.str();
1709412Sandreas.hansson@arm.com    }
1719412Sandreas.hansson@arm.com
1729412Sandreas.hansson@arm.com    void
1739412Sandreas.hansson@arm.com    InitInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
17410676Sandreas.hansson@arm.com    {
1759412Sandreas.hansson@arm.com        DPRINTF(Faults, "Init interrupt.\n");
1769412Sandreas.hansson@arm.com        // The otherwise unmodified integer registers should be set to 0.
1779412Sandreas.hansson@arm.com        for (int index = 0; index < NUM_INTREGS; index++) {
1789412Sandreas.hansson@arm.com            tc->setIntReg(index, 0);
1799412Sandreas.hansson@arm.com        }
1809411Sandreas.hansson@arm.com
1819411Sandreas.hansson@arm.com        CR0 cr0 = tc->readMiscReg(MISCREG_CR0);
1829411Sandreas.hansson@arm.com        CR0 newCR0 = 1 << 4;
1839411Sandreas.hansson@arm.com        newCR0.cd = cr0.cd;
1849411Sandreas.hansson@arm.com        newCR0.nw = cr0.nw;
1859411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CR0, newCR0);
1869411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CR2, 0);
18710676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CR3, 0);
18810676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CR4, 0);
18910676Sandreas.hansson@arm.com
19010676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL);
19110676Sandreas.hansson@arm.com
1929411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_EFER, 0);
1939411Sandreas.hansson@arm.com
1949411Sandreas.hansson@arm.com        SegAttr dataAttr = 0;
1959411Sandreas.hansson@arm.com        dataAttr.dpl = 0;
1969581Sandreas.hansson@arm.com        dataAttr.unusable = 0;
1979581Sandreas.hansson@arm.com        dataAttr.defaultSize = 0;
1989780Sandreas.hansson@arm.com        dataAttr.longMode = 0;
1999581Sandreas.hansson@arm.com        dataAttr.avl = 0;
2009411Sandreas.hansson@arm.com        dataAttr.granularity = 0;
2019411Sandreas.hansson@arm.com        dataAttr.present = 1;
2029411Sandreas.hansson@arm.com        dataAttr.type = 3;
2039411Sandreas.hansson@arm.com        dataAttr.writable = 1;
2049411Sandreas.hansson@arm.com        dataAttr.readable = 1;
2059411Sandreas.hansson@arm.com        dataAttr.expandDown = 0;
2069411Sandreas.hansson@arm.com        dataAttr.system = 1;
2079411Sandreas.hansson@arm.com
2089411Sandreas.hansson@arm.com        for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) {
2099411Sandreas.hansson@arm.com            tc->setMiscReg(MISCREG_SEG_SEL(seg), 0);
2109405Sandreas.hansson@arm.com            tc->setMiscReg(MISCREG_SEG_BASE(seg), 0);
2119411Sandreas.hansson@arm.com            tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0);
2129411Sandreas.hansson@arm.com            tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff);
2139405Sandreas.hansson@arm.com            tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr);
2149411Sandreas.hansson@arm.com        }
2159411Sandreas.hansson@arm.com
2169411Sandreas.hansson@arm.com        SegAttr codeAttr = 0;
2179411Sandreas.hansson@arm.com        codeAttr.dpl = 0;
218532SN/A        codeAttr.unusable = 0;
2199405Sandreas.hansson@arm.com        codeAttr.defaultSize = 0;
2209405Sandreas.hansson@arm.com        codeAttr.longMode = 0;
2219405Sandreas.hansson@arm.com        codeAttr.avl = 0;
22210435Snilay@cs.wisc.edu        codeAttr.granularity = 0;
2239405Sandreas.hansson@arm.com        codeAttr.present = 1;
2249405Sandreas.hansson@arm.com        codeAttr.type = 10;
2259405Sandreas.hansson@arm.com        codeAttr.writable = 0;
2269405Sandreas.hansson@arm.com        codeAttr.readable = 1;
2279405Sandreas.hansson@arm.com        codeAttr.expandDown = 0;
2289405Sandreas.hansson@arm.com        codeAttr.system = 1;
2299405Sandreas.hansson@arm.com
23010678SCurtis.Dunham@arm.com        tc->setMiscReg(MISCREG_CS, 0xf000);
23110678SCurtis.Dunham@arm.com        tc->setMiscReg(MISCREG_CS_BASE,
23210678SCurtis.Dunham@arm.com                0x00000000ffff0000ULL);
23310678SCurtis.Dunham@arm.com        tc->setMiscReg(MISCREG_CS_EFF_BASE,
23410678SCurtis.Dunham@arm.com                0x00000000ffff0000ULL);
2359405Sandreas.hansson@arm.com        // This has the base value pre-added.
2369405Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
2379405Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);
2389405Sandreas.hansson@arm.com
2399405Sandreas.hansson@arm.com        PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE));
2409405Sandreas.hansson@arm.com        tc->pcState(pc);
24110676Sandreas.hansson@arm.com
24210676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TSG_BASE, 0);
24310676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);
24410676Sandreas.hansson@arm.com
24510676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_IDTR_BASE, 0);
24610676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);
24710676Sandreas.hansson@arm.com
24810676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TSL, 0);
24910676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TSL_BASE, 0);
25010676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff);
25110676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TSL_ATTR, 0);
25210676Sandreas.hansson@arm.com
25310676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TR, 0);
25410676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TR_BASE, 0);
2559411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff);
25610676Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_TR_ATTR, 0);
2579411Sandreas.hansson@arm.com
2589411Sandreas.hansson@arm.com        // This value should be the family/model/stepping of the processor.
2599411Sandreas.hansson@arm.com        // (page 418). It should be consistent with the value from CPUID, but
2609411Sandreas.hansson@arm.com        // the actual value probably doesn't matter much.
2619411Sandreas.hansson@arm.com        tc->setIntReg(INTREG_RDX, 0);
2629411Sandreas.hansson@arm.com
2639411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_DR0, 0);
2649411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_DR1, 0);
2659411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_DR2, 0);
2669411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_DR3, 0);
2679411Sandreas.hansson@arm.com
2689411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL);
2699411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL);
2709411Sandreas.hansson@arm.com
27110676Sandreas.hansson@arm.com        // Update the handy M5 Reg.
2729411Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_M5_REG, 0);
2739405Sandreas.hansson@arm.com        MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt;
2749279Sandreas.hansson@arm.com        pc.upc(romMicroPC(entry));
2759279Sandreas.hansson@arm.com        pc.nupc(romMicroPC(entry) + 1);
2769279Sandreas.hansson@arm.com        tc->pcState(pc);
2779279Sandreas.hansson@arm.com    }
2789279Sandreas.hansson@arm.com
2799279Sandreas.hansson@arm.com    void
2809279Sandreas.hansson@arm.com    StartupInterrupt::invoke(ThreadContext *tc, StaticInstPtr inst)
2819279Sandreas.hansson@arm.com    {
2829279Sandreas.hansson@arm.com        DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector);
2839279Sandreas.hansson@arm.com        HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG);
2849279Sandreas.hansson@arm.com        if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) {
28510853Sandreas.hansson@arm.com            panic("Startup IPI recived outside of real mode. "
28610853Sandreas.hansson@arm.com                    "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode);
28710853Sandreas.hansson@arm.com        }
28810853Sandreas.hansson@arm.com
28910853Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CS, vector << 8);
29010853Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CS_BASE, vector << 12);
29110853Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12);
2929411Sandreas.hansson@arm.com        // This has the base value pre-added.
29310853Sandreas.hansson@arm.com        tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff);
2949411Sandreas.hansson@arm.com
2959411Sandreas.hansson@arm.com        tc->pcState(tc->readMiscReg(MISCREG_CS_BASE));
2969411Sandreas.hansson@arm.com    }
2979411Sandreas.hansson@arm.com} // namespace X86ISA
2989411Sandreas.hansson@arm.com
2999411Sandreas.hansson@arm.com