faults.cc revision 12511
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Gabe Black 29 * Kevin Lim 30 */ 31 32#include "arch/sparc/faults.hh" 33 34#include <algorithm> 35 36#include "arch/sparc/isa_traits.hh" 37#include "arch/sparc/process.hh" 38#include "arch/sparc/tlb.hh" 39#include "arch/sparc/types.hh" 40#include "base/bitfield.hh" 41#include "base/trace.hh" 42#include "cpu/base.hh" 43#include "cpu/thread_context.hh" 44#include "mem/page_table.hh" 45#include "sim/full_system.hh" 46#include "sim/process.hh" 47 48using namespace std; 49 50namespace SparcISA 51{ 52 53template<> SparcFaultBase::FaultVals 54 SparcFault<PowerOnReset>::vals = 55{"power_on_reset", 0x001, 0, {H, H, H}, FaultStat()}; 56 57template<> SparcFaultBase::FaultVals 58 SparcFault<WatchDogReset>::vals = 59{"watch_dog_reset", 0x002, 120, {H, H, H}, FaultStat()}; 60 61template<> SparcFaultBase::FaultVals 62 SparcFault<ExternallyInitiatedReset>::vals = 63{"externally_initiated_reset", 0x003, 110, {H, H, H}, FaultStat()}; 64 65template<> SparcFaultBase::FaultVals 66 SparcFault<SoftwareInitiatedReset>::vals = 67{"software_initiated_reset", 0x004, 130, {SH, SH, H}, FaultStat()}; 68 69template<> SparcFaultBase::FaultVals 70 SparcFault<REDStateException>::vals = 71{"RED_state_exception", 0x005, 1, {H, H, H}, FaultStat()}; 72 73template<> SparcFaultBase::FaultVals 74 SparcFault<StoreError>::vals = 75{"store_error", 0x007, 201, {H, H, H}, FaultStat()}; 76 77template<> SparcFaultBase::FaultVals 78 SparcFault<InstructionAccessException>::vals = 79{"instruction_access_exception", 0x008, 300, {H, H, H}, FaultStat()}; 80 81//XXX This trap is apparently dropped from ua2005 82/*template<> SparcFaultBase::FaultVals 83 SparcFault<InstructionAccessMMUMiss>::vals = 84 {"inst_mmu", 0x009, 2, {H, H, H}};*/ 85 86template<> SparcFaultBase::FaultVals 87 SparcFault<InstructionAccessError>::vals = 88{"instruction_access_error", 0x00A, 400, {H, H, H}, FaultStat()}; 89 90template<> SparcFaultBase::FaultVals 91 SparcFault<IllegalInstruction>::vals = 92{"illegal_instruction", 0x010, 620, {H, H, H}, FaultStat()}; 93 94template<> SparcFaultBase::FaultVals 95 SparcFault<PrivilegedOpcode>::vals = 96{"privileged_opcode", 0x011, 700, {P, SH, SH}, FaultStat()}; 97 98//XXX This trap is apparently dropped from ua2005 99/*template<> SparcFaultBase::FaultVals 100 SparcFault<UnimplementedLDD>::vals = 101 {"unimp_ldd", 0x012, 6, {H, H, H}};*/ 102 103//XXX This trap is apparently dropped from ua2005 104/*template<> SparcFaultBase::FaultVals 105 SparcFault<UnimplementedSTD>::vals = 106 {"unimp_std", 0x013, 6, {H, H, H}};*/ 107 108template<> SparcFaultBase::FaultVals 109 SparcFault<FpDisabled>::vals = 110{"fp_disabled", 0x020, 800, {P, P, H}, FaultStat()}; 111 112/* SPARCv8 and SPARCv9 define just fp_disabled trap. SIMD is not contemplated 113 * as a separate part. Therefore, we use the same code and TT */ 114template<> SparcFaultBase::FaultVals 115 SparcFault<VecDisabled>::vals = 116{"fp_disabled", 0x020, 800, {P, P, H}, FaultStat()}; 117 118template<> SparcFaultBase::FaultVals 119 SparcFault<FpExceptionIEEE754>::vals = 120{"fp_exception_ieee_754", 0x021, 1110, {P, P, H}, FaultStat()}; 121 122template<> SparcFaultBase::FaultVals 123 SparcFault<FpExceptionOther>::vals = 124{"fp_exception_other", 0x022, 1110, {P, P, H}, FaultStat()}; 125 126template<> SparcFaultBase::FaultVals 127 SparcFault<TagOverflow>::vals = 128{"tag_overflow", 0x023, 1400, {P, P, H}, FaultStat()}; 129 130template<> SparcFaultBase::FaultVals 131 SparcFault<CleanWindow>::vals = 132{"clean_window", 0x024, 1010, {P, P, H}, FaultStat()}; 133 134template<> SparcFaultBase::FaultVals 135 SparcFault<DivisionByZero>::vals = 136{"division_by_zero", 0x028, 1500, {P, P, H}, FaultStat()}; 137 138template<> SparcFaultBase::FaultVals 139 SparcFault<InternalProcessorError>::vals = 140{"internal_processor_error", 0x029, 4, {H, H, H}, FaultStat()}; 141 142template<> SparcFaultBase::FaultVals 143 SparcFault<InstructionInvalidTSBEntry>::vals = 144{"instruction_invalid_tsb_entry", 0x02A, 210, {H, H, SH}, FaultStat()}; 145 146template<> SparcFaultBase::FaultVals 147 SparcFault<DataInvalidTSBEntry>::vals = 148{"data_invalid_tsb_entry", 0x02B, 1203, {H, H, H}, FaultStat()}; 149 150template<> SparcFaultBase::FaultVals 151 SparcFault<DataAccessException>::vals = 152{"data_access_exception", 0x030, 1201, {H, H, H}, FaultStat()}; 153 154//XXX This trap is apparently dropped from ua2005 155/*template<> SparcFaultBase::FaultVals 156 SparcFault<DataAccessMMUMiss>::vals = 157 {"data_mmu", 0x031, 12, {H, H, H}};*/ 158 159template<> SparcFaultBase::FaultVals 160 SparcFault<DataAccessError>::vals = 161{"data_access_error", 0x032, 1210, {H, H, H}, FaultStat()}; 162 163template<> SparcFaultBase::FaultVals 164 SparcFault<DataAccessProtection>::vals = 165{"data_access_protection", 0x033, 1207, {H, H, H}, FaultStat()}; 166 167template<> SparcFaultBase::FaultVals 168 SparcFault<MemAddressNotAligned>::vals = 169{"mem_address_not_aligned", 0x034, 1020, {H, H, H}, FaultStat()}; 170 171template<> SparcFaultBase::FaultVals 172 SparcFault<LDDFMemAddressNotAligned>::vals = 173{"LDDF_mem_address_not_aligned", 0x035, 1010, {H, H, H}, FaultStat()}; 174 175template<> SparcFaultBase::FaultVals 176 SparcFault<STDFMemAddressNotAligned>::vals = 177{"STDF_mem_address_not_aligned", 0x036, 1010, {H, H, H}, FaultStat()}; 178 179template<> SparcFaultBase::FaultVals 180 SparcFault<PrivilegedAction>::vals = 181{"privileged_action", 0x037, 1110, {H, H, SH}, FaultStat()}; 182 183template<> SparcFaultBase::FaultVals 184 SparcFault<LDQFMemAddressNotAligned>::vals = 185{"LDQF_mem_address_not_aligned", 0x038, 1010, {H, H, H}, FaultStat()}; 186 187template<> SparcFaultBase::FaultVals 188 SparcFault<STQFMemAddressNotAligned>::vals = 189{"STQF_mem_address_not_aligned", 0x039, 1010, {H, H, H}, FaultStat()}; 190 191template<> SparcFaultBase::FaultVals 192 SparcFault<InstructionRealTranslationMiss>::vals = 193{"instruction_real_translation_miss", 0x03E, 208, {H, H, SH}, FaultStat()}; 194 195template<> SparcFaultBase::FaultVals 196 SparcFault<DataRealTranslationMiss>::vals = 197{"data_real_translation_miss", 0x03F, 1203, {H, H, H}, FaultStat()}; 198 199//XXX This trap is apparently dropped from ua2005 200/*template<> SparcFaultBase::FaultVals 201 SparcFault<AsyncDataError>::vals = 202 {"async_data", 0x040, 2, {H, H, H}};*/ 203 204template<> SparcFaultBase::FaultVals 205 SparcFault<InterruptLevelN>::vals = 206{"interrupt_level_n", 0x040, 0, {P, P, SH}, FaultStat()}; 207 208template<> SparcFaultBase::FaultVals 209 SparcFault<HstickMatch>::vals = 210{"hstick_match", 0x05E, 1601, {H, H, H}, FaultStat()}; 211 212template<> SparcFaultBase::FaultVals 213 SparcFault<TrapLevelZero>::vals = 214{"trap_level_zero", 0x05F, 202, {H, H, SH}, FaultStat()}; 215 216template<> SparcFaultBase::FaultVals 217 SparcFault<InterruptVector>::vals = 218{"interrupt_vector", 0x060, 2630, {H, H, H}, FaultStat()}; 219 220template<> SparcFaultBase::FaultVals 221 SparcFault<PAWatchpoint>::vals = 222{"PA_watchpoint", 0x061, 1209, {H, H, H}, FaultStat()}; 223 224template<> SparcFaultBase::FaultVals 225 SparcFault<VAWatchpoint>::vals = 226{"VA_watchpoint", 0x062, 1120, {P, P, SH}, FaultStat()}; 227 228template<> SparcFaultBase::FaultVals 229 SparcFault<FastInstructionAccessMMUMiss>::vals = 230{"fast_instruction_access_MMU_miss", 0x064, 208, {H, H, SH}, FaultStat()}; 231 232template<> SparcFaultBase::FaultVals 233 SparcFault<FastDataAccessMMUMiss>::vals = 234{"fast_data_access_MMU_miss", 0x068, 1203, {H, H, H}, FaultStat()}; 235 236template<> SparcFaultBase::FaultVals 237 SparcFault<FastDataAccessProtection>::vals = 238{"fast_data_access_protection", 0x06C, 1207, {H, H, H}, FaultStat()}; 239 240template<> SparcFaultBase::FaultVals 241 SparcFault<InstructionBreakpoint>::vals = 242{"instruction_break", 0x076, 610, {H, H, H}, FaultStat()}; 243 244template<> SparcFaultBase::FaultVals 245 SparcFault<CpuMondo>::vals = 246{"cpu_mondo", 0x07C, 1608, {P, P, SH}, FaultStat()}; 247 248template<> SparcFaultBase::FaultVals 249 SparcFault<DevMondo>::vals = 250{"dev_mondo", 0x07D, 1611, {P, P, SH}, FaultStat()}; 251 252template<> SparcFaultBase::FaultVals 253 SparcFault<ResumableError>::vals = 254{"resume_error", 0x07E, 3330, {P, P, SH}, FaultStat()}; 255 256template<> SparcFaultBase::FaultVals 257 SparcFault<SpillNNormal>::vals = 258{"spill_n_normal", 0x080, 900, {P, P, H}, FaultStat()}; 259 260template<> SparcFaultBase::FaultVals 261 SparcFault<SpillNOther>::vals = 262{"spill_n_other", 0x0A0, 900, {P, P, H}, FaultStat()}; 263 264template<> SparcFaultBase::FaultVals 265 SparcFault<FillNNormal>::vals = 266{"fill_n_normal", 0x0C0, 900, {P, P, H}, FaultStat()}; 267 268template<> SparcFaultBase::FaultVals 269 SparcFault<FillNOther>::vals = 270{"fill_n_other", 0x0E0, 900, {P, P, H}, FaultStat()}; 271 272template<> SparcFaultBase::FaultVals 273 SparcFault<TrapInstruction>::vals = 274{"trap_instruction", 0x100, 1602, {P, P, H}, FaultStat()}; 275 276/** 277 * This causes the thread context to enter RED state. This causes the side 278 * effects which go with entering RED state because of a trap. 279 */ 280 281void 282enterREDState(ThreadContext *tc) 283{ 284 //@todo Disable the mmu? 285 //@todo Disable watchpoints? 286 HPSTATE hpstate= tc->readMiscRegNoEffect(MISCREG_HPSTATE); 287 hpstate.red = 1; 288 hpstate.hpriv = 1; 289 tc->setMiscReg(MISCREG_HPSTATE, hpstate); 290 // PSTATE.priv is set to 1 here. The manual says it should be 0, but 291 // Legion sets it to 1. 292 PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); 293 pstate.priv = 1; 294 tc->setMiscReg(MISCREG_PSTATE, pstate); 295} 296 297/** 298 * This sets everything up for a RED state trap except for actually jumping to 299 * the handler. 300 */ 301 302void 303doREDFault(ThreadContext *tc, TrapType tt) 304{ 305 MiscReg TL = tc->readMiscRegNoEffect(MISCREG_TL); 306 MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE); 307 PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); 308 HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); 309 MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2); 310 MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI); 311 MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP); 312 MiscReg CANSAVE = tc->readMiscRegNoEffect(NumIntArchRegs + 3); 313 MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL); 314 PCState pc = tc->pcState(); 315 316 TL++; 317 318 Addr pcMask = pstate.am ? mask(32) : mask(64); 319 320 // set TSTATE.gl to gl 321 replaceBits(TSTATE, 42, 40, GL); 322 // set TSTATE.ccr to ccr 323 replaceBits(TSTATE, 39, 32, CCR); 324 // set TSTATE.asi to asi 325 replaceBits(TSTATE, 31, 24, ASI); 326 // set TSTATE.pstate to pstate 327 replaceBits(TSTATE, 20, 8, pstate); 328 // set TSTATE.cwp to cwp 329 replaceBits(TSTATE, 4, 0, CWP); 330 331 // Write back TSTATE 332 tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE); 333 334 // set TPC to PC 335 tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask); 336 // set TNPC to NPC 337 tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask); 338 339 // set HTSTATE.hpstate to hpstate 340 tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate); 341 342 // TT = trap type; 343 tc->setMiscRegNoEffect(MISCREG_TT, tt); 344 345 // Update GL 346 tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL)); 347 348 bool priv = pstate.priv; // just save the priv bit 349 pstate = 0; 350 pstate.priv = priv; 351 pstate.pef = 1; 352 tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); 353 354 hpstate.red = 1; 355 hpstate.hpriv = 1; 356 hpstate.ibe = 0; 357 hpstate.tlz = 0; 358 tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate); 359 360 bool changedCWP = true; 361 if (tt == 0x24) 362 CWP++; 363 else if (0x80 <= tt && tt <= 0xbf) 364 CWP += (CANSAVE + 2); 365 else if (0xc0 <= tt && tt <= 0xff) 366 CWP--; 367 else 368 changedCWP = false; 369 370 if (changedCWP) { 371 CWP = (CWP + NWindows) % NWindows; 372 tc->setMiscReg(MISCREG_CWP, CWP); 373 } 374} 375 376/** 377 * This sets everything up for a normal trap except for actually jumping to 378 * the handler. 379 */ 380 381void 382doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) 383{ 384 MiscReg TL = tc->readMiscRegNoEffect(MISCREG_TL); 385 MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE); 386 PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); 387 HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); 388 MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2); 389 MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI); 390 MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP); 391 MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3); 392 MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL); 393 PCState pc = tc->pcState(); 394 395 // Increment the trap level 396 TL++; 397 tc->setMiscRegNoEffect(MISCREG_TL, TL); 398 399 Addr pcMask = pstate.am ? mask(32) : mask(64); 400 401 // Save off state 402 403 // set TSTATE.gl to gl 404 replaceBits(TSTATE, 42, 40, GL); 405 // set TSTATE.ccr to ccr 406 replaceBits(TSTATE, 39, 32, CCR); 407 // set TSTATE.asi to asi 408 replaceBits(TSTATE, 31, 24, ASI); 409 // set TSTATE.pstate to pstate 410 replaceBits(TSTATE, 20, 8, pstate); 411 // set TSTATE.cwp to cwp 412 replaceBits(TSTATE, 4, 0, CWP); 413 414 // Write back TSTATE 415 tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE); 416 417 // set TPC to PC 418 tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask); 419 // set TNPC to NPC 420 tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask); 421 422 // set HTSTATE.hpstate to hpstate 423 tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate); 424 425 // TT = trap type; 426 tc->setMiscRegNoEffect(MISCREG_TT, tt); 427 428 // Update the global register level 429 if (!gotoHpriv) 430 tc->setMiscReg(MISCREG_GL, min<int>(GL + 1, MaxPGL)); 431 else 432 tc->setMiscReg(MISCREG_GL, min<int>(GL + 1, MaxGL)); 433 434 // pstate.mm is unchanged 435 pstate.pef = 1; // PSTATE.pef = whether or not an fpu is present 436 pstate.am = 0; 437 pstate.ie = 0; 438 // pstate.tle is unchanged 439 // pstate.tct = 0 440 441 if (gotoHpriv) { 442 pstate.cle = 0; 443 // The manual says PSTATE.priv should be 0, but Legion leaves it alone 444 hpstate.red = 0; 445 hpstate.hpriv = 1; 446 hpstate.ibe = 0; 447 // hpstate.tlz is unchanged 448 tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate); 449 } else { // we are going to priv 450 pstate.priv = 1; 451 pstate.cle = pstate.tle; 452 } 453 tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); 454 455 456 bool changedCWP = true; 457 if (tt == 0x24) 458 CWP++; 459 else if (0x80 <= tt && tt <= 0xbf) 460 CWP += (CANSAVE + 2); 461 else if (0xc0 <= tt && tt <= 0xff) 462 CWP--; 463 else 464 changedCWP = false; 465 466 if (changedCWP) { 467 CWP = (CWP + NWindows) % NWindows; 468 tc->setMiscReg(MISCREG_CWP, CWP); 469 } 470} 471 472void 473getREDVector(MiscReg TT, Addr &PC, Addr &NPC) 474{ 475 //XXX The following constant might belong in a header file. 476 const Addr RSTVAddr = 0xFFF0000000ULL; 477 PC = RSTVAddr | ((TT << 5) & 0xFF); 478 NPC = PC + sizeof(MachInst); 479} 480 481void 482getHyperVector(ThreadContext * tc, Addr &PC, Addr &NPC, MiscReg TT) 483{ 484 Addr HTBA = tc->readMiscRegNoEffect(MISCREG_HTBA); 485 PC = (HTBA & ~mask(14)) | ((TT << 5) & mask(14)); 486 NPC = PC + sizeof(MachInst); 487} 488 489void 490getPrivVector(ThreadContext *tc, Addr &PC, Addr &NPC, MiscReg TT, MiscReg TL) 491{ 492 Addr TBA = tc->readMiscRegNoEffect(MISCREG_TBA); 493 PC = (TBA & ~mask(15)) | 494 (TL > 1 ? (1 << 14) : 0) | 495 ((TT << 5) & mask(14)); 496 NPC = PC + sizeof(MachInst); 497} 498 499void 500SparcFaultBase::invoke(ThreadContext * tc, const StaticInstPtr &inst) 501{ 502 FaultBase::invoke(tc); 503 if (!FullSystem) 504 return; 505 506 countStat()++; 507 508 // We can refer to this to see what the trap level -was-, but something 509 // in the middle could change it in the regfile out from under us. 510 MiscReg tl = tc->readMiscRegNoEffect(MISCREG_TL); 511 MiscReg tt = tc->readMiscRegNoEffect(MISCREG_TT); 512 PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); 513 HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); 514 515 Addr PC, NPC; 516 517 PrivilegeLevel current; 518 if (hpstate.hpriv) 519 current = Hyperprivileged; 520 else if (pstate.priv) 521 current = Privileged; 522 else 523 current = User; 524 525 PrivilegeLevel level = getNextLevel(current); 526 527 if (hpstate.red || (tl == MaxTL - 1)) { 528 getREDVector(5, PC, NPC); 529 doREDFault(tc, tt); 530 // This changes the hpstate and pstate, so we need to make sure we 531 // save the old version on the trap stack in doREDFault. 532 enterREDState(tc); 533 } else if (tl == MaxTL) { 534 panic("Should go to error state here.. crap\n"); 535 // Do error_state somehow? 536 // Probably inject a WDR fault using the interrupt mechanism. 537 // What should the PC and NPC be set to? 538 } else if (tl > MaxPTL && level == Privileged) { 539 // guest_watchdog fault 540 doNormalFault(tc, trapType(), true); 541 getHyperVector(tc, PC, NPC, 2); 542 } else if (level == Hyperprivileged || 543 (level == Privileged && trapType() >= 384)) { 544 doNormalFault(tc, trapType(), true); 545 getHyperVector(tc, PC, NPC, trapType()); 546 } else { 547 doNormalFault(tc, trapType(), false); 548 getPrivVector(tc, PC, NPC, trapType(), tl + 1); 549 } 550 551 PCState pc; 552 pc.pc(PC); 553 pc.npc(NPC); 554 pc.nnpc(NPC + sizeof(MachInst)); 555 pc.upc(0); 556 pc.nupc(1); 557 tc->pcState(pc); 558} 559 560void 561PowerOnReset::invoke(ThreadContext *tc, const StaticInstPtr &inst) 562{ 563 // For SPARC, when a system is first started, there is a power 564 // on reset Trap which sets the processor into the following state. 565 // Bits that aren't set aren't defined on startup. 566 567 tc->setMiscRegNoEffect(MISCREG_TL, MaxTL); 568 tc->setMiscRegNoEffect(MISCREG_TT, trapType()); 569 tc->setMiscReg(MISCREG_GL, MaxGL); 570 571 PSTATE pstate = 0; 572 pstate.pef = 1; 573 pstate.priv = 1; 574 tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate); 575 576 // Turn on red and hpriv, set everything else to 0 577 HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); 578 hpstate.red = 1; 579 hpstate.hpriv = 1; 580 hpstate.ibe = 0; 581 hpstate.tlz = 0; 582 tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate); 583 584 // The tick register is unreadable by nonprivileged software 585 tc->setMiscRegNoEffect(MISCREG_TICK, 1ULL << 63); 586 587 // Enter RED state. We do this last so that the actual state preserved in 588 // the trap stack is the state from before this fault. 589 enterREDState(tc); 590 591 Addr PC, NPC; 592 getREDVector(trapType(), PC, NPC); 593 594 PCState pc; 595 pc.pc(PC); 596 pc.npc(NPC); 597 pc.nnpc(NPC + sizeof(MachInst)); 598 pc.upc(0); 599 pc.nupc(1); 600 tc->pcState(pc); 601 602 // These registers are specified as "undefined" after a POR, and they 603 // should have reasonable values after the miscregfile is reset 604 /* 605 // Clear all the soft interrupt bits 606 softint = 0; 607 // disable timer compare interrupts, reset tick_cmpr 608 tc->setMiscRegNoEffect(MISCREG_ 609 tick_cmprFields.int_dis = 1; 610 tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing 611 stickFields.npt = 1; // The TICK register is unreadable by by !priv 612 stick_cmprFields.int_dis = 1; // disable timer compare interrupts 613 stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing 614 615 tt[tl] = _trapType; 616 617 hintp = 0; // no interrupts pending 618 hstick_cmprFields.int_dis = 1; // disable timer compare interrupts 619 hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing 620 */ 621} 622 623void 624FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, 625 const StaticInstPtr &inst) 626{ 627 if (FullSystem) { 628 SparcFaultBase::invoke(tc, inst); 629 return; 630 } 631 632 Process *p = tc->getProcessPtr(); 633 const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); 634 panic_if(!pte, "Tried to execute unmapped address %#x.\n", vaddr); 635 636 Addr alignedvaddr = p->pTable->pageAlign(vaddr); 637 638 // Grab fields used during instruction translation to figure out 639 // which context to use. 640 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); 641 642 // Inside a VM, a real address is the address that guest OS would 643 // interpret to be a physical address. To map to the physical address, 644 // it still needs to undergo a translation. The instruction 645 // translation code in the SPARC ITLB code assumes that the context is 646 // zero (kernel-level) if real addressing is being used. 647 bool is_real_address = !bits(tlbdata, 4); 648 649 // The SPARC ITLB code assumes that traps are executed in context 650 // zero so we carry that assumption through here. 651 bool trapped = bits(tlbdata, 18, 16) > 0; 652 653 // The primary context acts as a PASID. It allows the MMU to 654 // distinguish between virtual addresses that would alias to the 655 // same physical address (if two or more processes shared the same 656 // virtual address mapping). 657 int primary_context = bits(tlbdata, 47, 32); 658 659 // The partition id distinguishes between virtualized environments. 660 int const partition_id = 0; 661 662 // Given the assumptions in the translateInst code in the SPARC ITLB, 663 // the logic works out to the following for the context. 664 int context_id = (is_real_address || trapped) ? 0 : primary_context; 665 666 TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr, 667 pte->flags & EmulationPageTable::Uncacheable, 668 pte->flags & EmulationPageTable::ReadOnly); 669 670 // Insert the TLB entry. 671 // The entry specifying whether the address is "real" is set to 672 // false for syscall emulation mode regardless of whether the 673 // address is real in preceding code. Not sure sure that this is 674 // correct, but also not sure if it matters at all. 675 dynamic_cast<TLB *>(tc->getITBPtr())-> 676 insert(alignedvaddr, partition_id, context_id, false, entry.pte); 677} 678 679void 680FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst) 681{ 682 if (FullSystem) { 683 SparcFaultBase::invoke(tc, inst); 684 return; 685 } 686 687 Process *p = tc->getProcessPtr(); 688 const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); 689 if (!pte && p->fixupStackFault(vaddr)) 690 pte = p->pTable->lookup(vaddr); 691 panic_if(!pte, "Tried to access unmapped address %#x.\n", vaddr); 692 693 Addr alignedvaddr = p->pTable->pageAlign(vaddr); 694 695 // Grab fields used during data translation to figure out 696 // which context to use. 697 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); 698 699 // The primary context acts as a PASID. It allows the MMU to 700 // distinguish between virtual addresses that would alias to the 701 // same physical address (if two or more processes shared the same 702 // virtual address mapping). There's a secondary context used in the 703 // DTLB translation code, but it should __probably__ be zero for 704 // syscall emulation code. (The secondary context is used by Solaris 705 // to allow kernel privilege code to access user space code: 706 // [ISBN 0-13-022496-0]:PG199.) 707 int primary_context = bits(tlbdata, 47, 32); 708 709 // "Hyper-Privileged Mode" is in use. There are three main modes of 710 // operation for Sparc: Hyper-Privileged Mode, Privileged Mode, and 711 // User Mode. 712 int hpriv = bits(tlbdata, 0); 713 714 // Reset, Error and Debug state is in use. Something horrible has 715 // happened or the system is operating in Reset Mode. 716 int red = bits(tlbdata, 1); 717 718 // Inside a VM, a real address is the address that guest OS would 719 // interpret to be a physical address. To map to the physical address, 720 // it still needs to undergo a translation. The instruction 721 // translation code in the SPARC ITLB code assumes that the context is 722 // zero (kernel-level) if real addressing is being used. 723 int is_real_address = !bits(tlbdata, 5); 724 725 // Grab the address space identifier register from the thread context. 726 // XXX: Inspecting how setMiscReg and setMiscRegNoEffect behave for 727 // MISCREG_ASI causes me to think that the ASI register implementation 728 // might be bugged. The NoEffect variant changes the ASI register 729 // value in the architectural state while the normal variant changes 730 // the context field in the thread context's currently decoded request 731 // but does not directly affect the ASI register value in the 732 // architectural state. The ASI values and the context field in the 733 // request packet seem to have completely different uses. 734 MiscReg reg_asi = tc->readMiscRegNoEffect(MISCREG_ASI); 735 ASI asi = static_cast<ASI>(reg_asi); 736 737 // The SPARC DTLB code assumes that traps are executed in context 738 // zero if the asi value is ASI_IMPLICIT (which is 0x0). There's also 739 // an assumption that the nucleus address space is being used, but 740 // the context is the relevant issue since we need to pass it to TLB. 741 bool trapped = bits(tlbdata, 18, 16) > 0; 742 743 // Given the assumptions in the translateData code in the SPARC DTLB, 744 // the logic works out to the following for the context. 745 int context_id = ((!hpriv && !red && is_real_address) || 746 asiIsReal(asi) || 747 (trapped && asi == ASI_IMPLICIT)) 748 ? 0 : primary_context; 749 750 // The partition id distinguishes between virtualized environments. 751 int const partition_id = 0; 752 753 TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr, 754 pte->flags & EmulationPageTable::Uncacheable, 755 pte->flags & EmulationPageTable::ReadOnly); 756 757 // Insert the TLB entry. 758 // The entry specifying whether the address is "real" is set to 759 // false for syscall emulation mode regardless of whether the 760 // address is real in preceding code. Not sure sure that this is 761 // correct, but also not sure if it matters at all. 762 dynamic_cast<TLB *>(tc->getDTBPtr())-> 763 insert(alignedvaddr, partition_id, context_id, false, entry.pte); 764} 765 766void 767SpillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst) 768{ 769 if (FullSystem) { 770 SparcFaultBase::invoke(tc, inst); 771 return; 772 } 773 774 doNormalFault(tc, trapType(), false); 775 776 Process *p = tc->getProcessPtr(); 777 778 SparcProcess *sp = dynamic_cast<SparcProcess *>(p); 779 assert(sp); 780 781 // Then adjust the PC and NPC 782 tc->pcState(sp->readSpillStart()); 783} 784 785void 786FillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst) 787{ 788 if (FullSystem) { 789 SparcFaultBase::invoke(tc, inst); 790 return; 791 } 792 793 doNormalFault(tc, trapType(), false); 794 795 Process *p = tc->getProcessPtr(); 796 797 SparcProcess *sp = dynamic_cast<SparcProcess *>(p); 798 assert(sp); 799 800 // Then adjust the PC and NPC 801 tc->pcState(sp->readFillStart()); 802} 803 804void 805TrapInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst) 806{ 807 if (FullSystem) { 808 SparcFaultBase::invoke(tc, inst); 809 return; 810 } 811 812 // In SE, this mechanism is how the process requests a service from 813 // the operating system. We'll get the process object from the thread 814 // context and let it service the request. 815 816 Process *p = tc->getProcessPtr(); 817 818 SparcProcess *sp = dynamic_cast<SparcProcess *>(p); 819 assert(sp); 820 821 Fault fault; 822 sp->handleTrap(_n, tc, &fault); 823 824 // We need to explicitly advance the pc, since that's not done for us 825 // on a faulting instruction 826 PCState pc = tc->pcState(); 827 pc.advance(); 828 tc->pcState(pc); 829} 830 831} // namespace SparcISA 832 833