faults.cc revision 12372:fd63af762679
112855Sgabeblack@google.com/* 212855Sgabeblack@google.com * Copyright (c) 2007 The Hewlett-Packard Development Company 312855Sgabeblack@google.com * All rights reserved. 412855Sgabeblack@google.com * 512855Sgabeblack@google.com * The license below extends only to copyright in the software and shall 612855Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712855Sgabeblack@google.com * property including but not limited to intellectual property relating 812855Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912855Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1012855Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112855Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1212855Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312855Sgabeblack@google.com * 1412855Sgabeblack@google.com * Copyright (c) 2003-2007 The Regents of The University of Michigan 1512855Sgabeblack@google.com * All rights reserved. 1612855Sgabeblack@google.com * 1712855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1812855Sgabeblack@google.com * modification, are permitted provided that the following conditions are 1912855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2012855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2112855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2212855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2312855Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2412855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2512855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2612855Sgabeblack@google.com * this software without specific prior written permission. 2712855Sgabeblack@google.com * 2812855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3812855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3912855Sgabeblack@google.com * 4012855Sgabeblack@google.com * Authors: Gabe Black 4112855Sgabeblack@google.com */ 4212855Sgabeblack@google.com 4312855Sgabeblack@google.com#include "arch/x86/faults.hh" 4412855Sgabeblack@google.com 4512855Sgabeblack@google.com#include "arch/x86/generated/decoder.hh" 4612855Sgabeblack@google.com#include "arch/x86/isa_traits.hh" 4712855Sgabeblack@google.com#include "base/loader/symtab.hh" 4812855Sgabeblack@google.com#include "base/trace.hh" 4912855Sgabeblack@google.com#include "cpu/thread_context.hh" 5012855Sgabeblack@google.com#include "debug/Faults.hh" 5112855Sgabeblack@google.com#include "sim/full_system.hh" 5212855Sgabeblack@google.com 5312855Sgabeblack@google.comnamespace X86ISA 5412855Sgabeblack@google.com{ 5512855Sgabeblack@google.com void X86FaultBase::invoke(ThreadContext * tc, const StaticInstPtr &inst) 5612855Sgabeblack@google.com { 5712855Sgabeblack@google.com if (!FullSystem) { 5812855Sgabeblack@google.com FaultBase::invoke(tc, inst); 5912855Sgabeblack@google.com return; 6012855Sgabeblack@google.com } 6112855Sgabeblack@google.com 6212855Sgabeblack@google.com PCState pcState = tc->pcState(); 6312855Sgabeblack@google.com Addr pc = pcState.pc(); 6412855Sgabeblack@google.com DPRINTF(Faults, "RIP %#x: vector %d: %s\n", 6512855Sgabeblack@google.com pc, vector, describe()); 6612855Sgabeblack@google.com using namespace X86ISAInst::RomLabels; 6712855Sgabeblack@google.com HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 6812855Sgabeblack@google.com MicroPC entry; 6912855Sgabeblack@google.com if (m5reg.mode == LongMode) { 70 if (isSoft()) { 71 entry = extern_label_longModeSoftInterrupt; 72 } else { 73 entry = extern_label_longModeInterrupt; 74 } 75 } else { 76 entry = extern_label_legacyModeInterrupt; 77 } 78 tc->setIntReg(INTREG_MICRO(1), vector); 79 tc->setIntReg(INTREG_MICRO(7), pc); 80 if (errorCode != (uint64_t)(-1)) { 81 if (m5reg.mode == LongMode) { 82 entry = extern_label_longModeInterruptWithError; 83 } else { 84 panic("Legacy mode interrupts with error codes " 85 "aren't implementde.\n"); 86 } 87 // Software interrupts shouldn't have error codes. If one 88 // does, there would need to be microcode to set it up. 89 assert(!isSoft()); 90 tc->setIntReg(INTREG_MICRO(15), errorCode); 91 } 92 pcState.upc(romMicroPC(entry)); 93 pcState.nupc(romMicroPC(entry) + 1); 94 tc->pcState(pcState); 95 } 96 97 std::string 98 X86FaultBase::describe() const 99 { 100 std::stringstream ss; 101 ccprintf(ss, "%s", mnemonic()); 102 if (errorCode != (uint64_t)(-1)) { 103 ccprintf(ss, "(%#x)", errorCode); 104 } 105 106 return ss.str(); 107 } 108 109 void X86Trap::invoke(ThreadContext * tc, const StaticInstPtr &inst) 110 { 111 X86FaultBase::invoke(tc); 112 if (!FullSystem) 113 return; 114 115 // This is the same as a fault, but it happens -after- the 116 // instruction. 117 PCState pc = tc->pcState(); 118 pc.uEnd(); 119 } 120 121 void X86Abort::invoke(ThreadContext * tc, const StaticInstPtr &inst) 122 { 123 panic("Abort exception!"); 124 } 125 126 void 127 InvalidOpcode::invoke(ThreadContext * tc, const StaticInstPtr &inst) 128 { 129 if (FullSystem) { 130 X86Fault::invoke(tc, inst); 131 } else { 132 panic("Unrecognized/invalid instruction executed:\n %s", 133 inst->machInst); 134 } 135 } 136 137 void PageFault::invoke(ThreadContext * tc, const StaticInstPtr &inst) 138 { 139 if (FullSystem) { 140 /* Invalidate any matching TLB entries before handling the page fault */ 141 tc->getITBPtr()->demapPage(addr, 0); 142 tc->getDTBPtr()->demapPage(addr, 0); 143 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 144 X86FaultBase::invoke(tc); 145 /* 146 * If something bad happens while trying to enter the page fault 147 * handler, I'm pretty sure that's a double fault and then all 148 * bets are off. That means it should be safe to update this 149 * state now. 150 */ 151 if (m5reg.mode == LongMode) { 152 tc->setMiscReg(MISCREG_CR2, addr); 153 } else { 154 tc->setMiscReg(MISCREG_CR2, (uint32_t)addr); 155 } 156 } else { 157 PageFaultErrorCode code = errorCode; 158 const char *modeStr = ""; 159 if (code.fetch) 160 modeStr = "execute"; 161 else if (code.write) 162 modeStr = "write"; 163 else 164 modeStr = "read"; 165 166 // print information about what we are panic'ing on 167 if (!inst) { 168 panic("Tried to %s unmapped address %#x.\n", modeStr, addr); 169 } else { 170 panic("Tried to %s unmapped address %#x.\nPC: %#x, Instr: %s", 171 modeStr, addr, tc->pcState().pc(), 172 inst->disassemble(tc->pcState().pc(), debugSymbolTable)); 173 } 174 } 175 } 176 177 std::string 178 PageFault::describe() const 179 { 180 std::stringstream ss; 181 ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr); 182 return ss.str(); 183 } 184 185 void 186 InitInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst) 187 { 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); 192 } 193 194 CR0 cr0 = tc->readMiscReg(MISCREG_CR0); 195 CR0 newCR0 = 1 << 4; 196 newCR0.cd = cr0.cd; 197 newCR0.nw = cr0.nw; 198 tc->setMiscReg(MISCREG_CR0, newCR0); 199 tc->setMiscReg(MISCREG_CR2, 0); 200 tc->setMiscReg(MISCREG_CR3, 0); 201 tc->setMiscReg(MISCREG_CR4, 0); 202 203 tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL); 204 205 tc->setMiscReg(MISCREG_EFER, 0); 206 207 SegAttr dataAttr = 0; 208 dataAttr.dpl = 0; 209 dataAttr.unusable = 0; 210 dataAttr.defaultSize = 0; 211 dataAttr.longMode = 0; 212 dataAttr.avl = 0; 213 dataAttr.granularity = 0; 214 dataAttr.present = 1; 215 dataAttr.type = 3; 216 dataAttr.writable = 1; 217 dataAttr.readable = 1; 218 dataAttr.expandDown = 0; 219 dataAttr.system = 1; 220 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); 227 } 228 229 SegAttr codeAttr = 0; 230 codeAttr.dpl = 0; 231 codeAttr.unusable = 0; 232 codeAttr.defaultSize = 0; 233 codeAttr.longMode = 0; 234 codeAttr.avl = 0; 235 codeAttr.granularity = 0; 236 codeAttr.present = 1; 237 codeAttr.type = 10; 238 codeAttr.writable = 0; 239 codeAttr.readable = 1; 240 codeAttr.expandDown = 0; 241 codeAttr.system = 1; 242 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); 251 252 PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE)); 253 tc->pcState(pc); 254 255 tc->setMiscReg(MISCREG_TSG_BASE, 0); 256 tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff); 257 258 tc->setMiscReg(MISCREG_IDTR_BASE, 0); 259 tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff); 260 261 SegAttr tslAttr = 0; 262 tslAttr.present = 1; 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); 268 269 SegAttr trAttr = 0; 270 trAttr.present = 1; 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); 276 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); 281 282 tc->setMiscReg(MISCREG_DR0, 0); 283 tc->setMiscReg(MISCREG_DR1, 0); 284 tc->setMiscReg(MISCREG_DR2, 0); 285 tc->setMiscReg(MISCREG_DR3, 0); 286 287 tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL); 288 tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL); 289 290 tc->setMiscReg(MISCREG_MXCSR, 0x1f80); 291 292 // Flag all elements on the x87 stack as empty. 293 tc->setMiscReg(MISCREG_FTW, 0xFFFF); 294 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); 300 tc->pcState(pc); 301 } 302 303 void 304 StartupInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst) 305 { 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); 311 } 312 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); 318 319 tc->pcState(tc->readMiscReg(MISCREG_CS_BASE)); 320 } 321} // namespace X86ISA 322 323