2 * Copyright (c) 2007 The Hewlett-Packard Development Company
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2003-2007 The Regents of The University of Michigan
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include "arch/x86/faults.hh"
43 #include "arch/x86/generated/decoder.hh"
44 #include "arch/x86/isa_traits.hh"
45 #include "base/loader/symtab.hh"
46 #include "base/trace.hh"
47 #include "cpu/thread_context.hh"
48 #include "debug/Faults.hh"
49 #include "sim/full_system.hh"
50 #include "sim/process.hh"
54 void X86FaultBase::invoke(ThreadContext
* tc
, const StaticInstPtr
&inst
)
57 FaultBase::invoke(tc
, inst
);
61 PCState pcState
= tc
->pcState();
62 Addr pc
= pcState
.pc();
63 DPRINTF(Faults
, "RIP %#x: vector %d: %s\n",
64 pc
, vector
, describe());
65 using namespace X86ISAInst::RomLabels
;
66 HandyM5Reg m5reg
= tc
->readMiscRegNoEffect(MISCREG_M5_REG
);
68 if (m5reg
.mode
== LongMode
) {
70 entry
= extern_label_longModeSoftInterrupt
;
72 entry
= extern_label_longModeInterrupt
;
75 entry
= extern_label_legacyModeInterrupt
;
77 tc
->setIntReg(INTREG_MICRO(1), vector
);
78 tc
->setIntReg(INTREG_MICRO(7), pc
);
79 if (errorCode
!= (uint64_t)(-1)) {
80 if (m5reg
.mode
== LongMode
) {
81 entry
= extern_label_longModeInterruptWithError
;
83 panic("Legacy mode interrupts with error codes "
84 "aren't implementde.\n");
86 // Software interrupts shouldn't have error codes. If one
87 // does, there would need to be microcode to set it up.
89 tc
->setIntReg(INTREG_MICRO(15), errorCode
);
91 pcState
.upc(romMicroPC(entry
));
92 pcState
.nupc(romMicroPC(entry
) + 1);
97 X86FaultBase::describe() const
100 ccprintf(ss
, "%s", mnemonic());
101 if (errorCode
!= (uint64_t)(-1)) {
102 ccprintf(ss
, "(%#x)", errorCode
);
108 void X86Trap::invoke(ThreadContext
* tc
, const StaticInstPtr
&inst
)
110 X86FaultBase::invoke(tc
);
114 // This is the same as a fault, but it happens -after- the
116 PCState pc
= tc
->pcState();
120 void X86Abort::invoke(ThreadContext
* tc
, const StaticInstPtr
&inst
)
122 panic("Abort exception!");
126 InvalidOpcode::invoke(ThreadContext
* tc
, const StaticInstPtr
&inst
)
129 X86Fault::invoke(tc
, inst
);
131 panic("Unrecognized/invalid instruction executed:\n %s",
136 void PageFault::invoke(ThreadContext
* tc
, const StaticInstPtr
&inst
)
139 /* Invalidate any matching TLB entries before handling the page fault */
140 tc
->getITBPtr()->demapPage(addr
, 0);
141 tc
->getDTBPtr()->demapPage(addr
, 0);
142 HandyM5Reg m5reg
= tc
->readMiscRegNoEffect(MISCREG_M5_REG
);
143 X86FaultBase::invoke(tc
);
145 * If something bad happens while trying to enter the page fault
146 * handler, I'm pretty sure that's a double fault and then all
147 * bets are off. That means it should be safe to update this
150 if (m5reg
.mode
== LongMode
) {
151 tc
->setMiscReg(MISCREG_CR2
, addr
);
153 tc
->setMiscReg(MISCREG_CR2
, (uint32_t)addr
);
155 } else if (!tc
->getProcessPtr()->fixupFault(addr
)) {
156 PageFaultErrorCode code
= errorCode
;
157 const char *modeStr
= "";
165 // print information about what we are panic'ing on
167 panic("Tried to %s unmapped address %#x.\n", modeStr
, addr
);
169 panic("Tried to %s unmapped address %#x.\nPC: %#x, Instr: %s",
170 modeStr
, addr
, tc
->pcState().pc(),
171 inst
->disassemble(tc
->pcState().pc(),
172 &Loader::debugSymbolTable
));
178 PageFault::describe() const
180 std::stringstream ss
;
181 ccprintf(ss
, "%s at %#x", X86FaultBase::describe(), addr
);
186 InitInterrupt::invoke(ThreadContext
*tc
, const StaticInstPtr
&inst
)
188 DPRINTF(Faults
, "Init interrupt.\n");
189 // The otherwise unmodified integer registers should be set to 0.
190 for (int index
= 0; index
< NUM_INTREGS
; index
++) {
191 tc
->setIntReg(index
, 0);
194 CR0 cr0
= tc
->readMiscReg(MISCREG_CR0
);
198 tc
->setMiscReg(MISCREG_CR0
, newCR0
);
199 tc
->setMiscReg(MISCREG_CR2
, 0);
200 tc
->setMiscReg(MISCREG_CR3
, 0);
201 tc
->setMiscReg(MISCREG_CR4
, 0);
203 tc
->setMiscReg(MISCREG_RFLAGS
, 0x0000000000000002ULL
);
205 tc
->setMiscReg(MISCREG_EFER
, 0);
207 SegAttr dataAttr
= 0;
209 dataAttr
.unusable
= 0;
210 dataAttr
.defaultSize
= 0;
211 dataAttr
.longMode
= 0;
213 dataAttr
.granularity
= 0;
214 dataAttr
.present
= 1;
216 dataAttr
.writable
= 1;
217 dataAttr
.readable
= 1;
218 dataAttr
.expandDown
= 0;
221 for (int seg
= 0; seg
!= NUM_SEGMENTREGS
; seg
++) {
222 tc
->setMiscReg(MISCREG_SEG_SEL(seg
), 0);
223 tc
->setMiscReg(MISCREG_SEG_BASE(seg
), 0);
224 tc
->setMiscReg(MISCREG_SEG_EFF_BASE(seg
), 0);
225 tc
->setMiscReg(MISCREG_SEG_LIMIT(seg
), 0xffff);
226 tc
->setMiscReg(MISCREG_SEG_ATTR(seg
), dataAttr
);
229 SegAttr codeAttr
= 0;
231 codeAttr
.unusable
= 0;
232 codeAttr
.defaultSize
= 0;
233 codeAttr
.longMode
= 0;
235 codeAttr
.granularity
= 0;
236 codeAttr
.present
= 1;
238 codeAttr
.writable
= 0;
239 codeAttr
.readable
= 1;
240 codeAttr
.expandDown
= 0;
243 tc
->setMiscReg(MISCREG_CS
, 0xf000);
244 tc
->setMiscReg(MISCREG_CS_BASE
,
245 0x00000000ffff0000ULL
);
246 tc
->setMiscReg(MISCREG_CS_EFF_BASE
,
247 0x00000000ffff0000ULL
);
248 // This has the base value pre-added.
249 tc
->setMiscReg(MISCREG_CS_LIMIT
, 0xffffffff);
250 tc
->setMiscReg(MISCREG_CS_ATTR
, codeAttr
);
252 PCState
pc(0x000000000000fff0ULL
+ tc
->readMiscReg(MISCREG_CS_BASE
));
255 tc
->setMiscReg(MISCREG_TSG_BASE
, 0);
256 tc
->setMiscReg(MISCREG_TSG_LIMIT
, 0xffff);
258 tc
->setMiscReg(MISCREG_IDTR_BASE
, 0);
259 tc
->setMiscReg(MISCREG_IDTR_LIMIT
, 0xffff);
263 tslAttr
.type
= 2; // LDT
264 tc
->setMiscReg(MISCREG_TSL
, 0);
265 tc
->setMiscReg(MISCREG_TSL_BASE
, 0);
266 tc
->setMiscReg(MISCREG_TSL_LIMIT
, 0xffff);
267 tc
->setMiscReg(MISCREG_TSL_ATTR
, tslAttr
);
271 trAttr
.type
= 3; // Busy 16-bit TSS
272 tc
->setMiscReg(MISCREG_TR
, 0);
273 tc
->setMiscReg(MISCREG_TR_BASE
, 0);
274 tc
->setMiscReg(MISCREG_TR_LIMIT
, 0xffff);
275 tc
->setMiscReg(MISCREG_TR_ATTR
, trAttr
);
277 // This value should be the family/model/stepping of the processor.
278 // (page 418). It should be consistent with the value from CPUID, but
279 // the actual value probably doesn't matter much.
280 tc
->setIntReg(INTREG_RDX
, 0);
282 tc
->setMiscReg(MISCREG_DR0
, 0);
283 tc
->setMiscReg(MISCREG_DR1
, 0);
284 tc
->setMiscReg(MISCREG_DR2
, 0);
285 tc
->setMiscReg(MISCREG_DR3
, 0);
287 tc
->setMiscReg(MISCREG_DR6
, 0x00000000ffff0ff0ULL
);
288 tc
->setMiscReg(MISCREG_DR7
, 0x0000000000000400ULL
);
290 tc
->setMiscReg(MISCREG_MXCSR
, 0x1f80);
292 // Flag all elements on the x87 stack as empty.
293 tc
->setMiscReg(MISCREG_FTW
, 0xFFFF);
295 // Update the handy M5 Reg.
296 tc
->setMiscReg(MISCREG_M5_REG
, 0);
297 MicroPC entry
= X86ISAInst::RomLabels::extern_label_initIntHalt
;
298 pc
.upc(romMicroPC(entry
));
299 pc
.nupc(romMicroPC(entry
) + 1);
304 StartupInterrupt::invoke(ThreadContext
*tc
, const StaticInstPtr
&inst
)
306 DPRINTF(Faults
, "Startup interrupt with vector %#x.\n", vector
);
307 HandyM5Reg m5Reg
= tc
->readMiscReg(MISCREG_M5_REG
);
308 if (m5Reg
.mode
!= LegacyMode
|| m5Reg
.submode
!= RealMode
) {
309 panic("Startup IPI recived outside of real mode. "
310 "Don't know what to do. %d, %d", m5Reg
.mode
, m5Reg
.submode
);
313 tc
->setMiscReg(MISCREG_CS
, vector
<< 8);
314 tc
->setMiscReg(MISCREG_CS_BASE
, vector
<< 12);
315 tc
->setMiscReg(MISCREG_CS_EFF_BASE
, vector
<< 12);
316 // This has the base value pre-added.
317 tc
->setMiscReg(MISCREG_CS_LIMIT
, 0xffff);
319 tc
->pcState(tc
->readMiscReg(MISCREG_CS_BASE
));
321 } // namespace X86ISA