faults.cc

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 713 行 · 第 1/2 页

CC
713
字号
    //set HPSTATE.tlz to 0    HPSTATE &= ~(1 << 0);    tc->setMiscRegNoEffect(MISCREG_HPSTATE, HPSTATE);    bool changedCWP = true;    if(tt == 0x24)        CWP++;    else if(0x80 <= tt && tt <= 0xbf)        CWP += (CANSAVE + 2);    else if(0xc0 <= tt && tt <= 0xff)        CWP--;    else        changedCWP = false;    if(changedCWP)    {        CWP = (CWP + NWindows) % NWindows;        tc->setMiscReg(MISCREG_CWP, CWP);    }}/** * This sets everything up for a normal trap except for actually jumping to * the handler. */void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv){    MiscReg TL = tc->readMiscRegNoEffect(MISCREG_TL);    MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE);    MiscReg PSTATE = tc->readMiscRegNoEffect(MISCREG_PSTATE);    MiscReg HPSTATE = tc->readMiscRegNoEffect(MISCREG_HPSTATE);    //MiscReg CCR = tc->readMiscRegNoEffect(MISCREG_CCR);    MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);    MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI);    MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP);    //MiscReg CANSAVE = tc->readMiscRegNoEffect(MISCREG_CANSAVE);    MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3);    MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);    MiscReg PC = tc->readPC();    MiscReg NPC = tc->readNextPC();    if (bits(PSTATE, 3,3)) {        PC &= mask(32);        NPC &= mask(32);    }    //Increment the trap level    TL++;    tc->setMiscRegNoEffect(MISCREG_TL, TL);    //Save off state    //set TSTATE.gl to gl    replaceBits(TSTATE, 42, 40, GL);    //set TSTATE.ccr to ccr    replaceBits(TSTATE, 39, 32, CCR);    //set TSTATE.asi to asi    replaceBits(TSTATE, 31, 24, ASI);    //set TSTATE.pstate to pstate    replaceBits(TSTATE, 20, 8, PSTATE);    //set TSTATE.cwp to cwp    replaceBits(TSTATE, 4, 0, CWP);    //Write back TSTATE    tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);    //set TPC to PC    tc->setMiscRegNoEffect(MISCREG_TPC, PC);    //set TNPC to NPC    tc->setMiscRegNoEffect(MISCREG_TNPC, NPC);    //set HTSTATE.hpstate to hpstate    tc->setMiscRegNoEffect(MISCREG_HTSTATE, HPSTATE);    //TT = trap type;    tc->setMiscRegNoEffect(MISCREG_TT, tt);    //Update the global register level    if (!gotoHpriv)        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxPGL));    else        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));    //PSTATE.mm is unchanged    PSTATE |= (1 << 4); //PSTATE.pef = whether or not an fpu is present    PSTATE &= ~(1 << 3); //PSTATE.am = 0    PSTATE &= ~(1 << 1); //PSTATE.ie = 0    //PSTATE.tle is unchanged    //PSTATE.tct = 0    if (gotoHpriv)    {        PSTATE &= ~(1 << 9); // PSTATE.cle = 0        //The manual says PSTATE.priv should be 0, but Legion leaves it alone        HPSTATE &= ~(1 << 5); //HPSTATE.red = 0        HPSTATE |= (1 << 2); //HPSTATE.hpriv = 1        HPSTATE &= ~(1 << 10); //HPSTATE.ibe = 0        //HPSTATE.tlz is unchanged        tc->setMiscRegNoEffect(MISCREG_HPSTATE, HPSTATE);    } else { // we are going to priv        PSTATE |= (1 << 2); //PSTATE.priv = 1        replaceBits(PSTATE, 9, 9, PSTATE >> 8); //PSTATE.cle = PSTATE.tle    }    tc->setMiscRegNoEffect(MISCREG_PSTATE, PSTATE);    bool changedCWP = true;    if (tt == 0x24)        CWP++;    else if (0x80 <= tt && tt <= 0xbf)        CWP += (CANSAVE + 2);    else if (0xc0 <= tt && tt <= 0xff)        CWP--;    else        changedCWP = false;    if (changedCWP)    {        CWP = (CWP + NWindows) % NWindows;        tc->setMiscReg(MISCREG_CWP, CWP);    }}void getREDVector(MiscReg TT, Addr & PC, Addr & NPC){    //XXX The following constant might belong in a header file.    const Addr RSTVAddr = 0xFFF0000000ULL;    PC = RSTVAddr | ((TT << 5) & 0xFF);    NPC = PC + sizeof(MachInst);}void getHyperVector(ThreadContext * tc, Addr & PC, Addr & NPC, MiscReg TT){    Addr HTBA = tc->readMiscRegNoEffect(MISCREG_HTBA);    PC = (HTBA & ~mask(14)) | ((TT << 5) & mask(14));    NPC = PC + sizeof(MachInst);}void getPrivVector(ThreadContext * tc, Addr & PC, Addr & NPC, MiscReg TT, MiscReg TL){    Addr TBA = tc->readMiscRegNoEffect(MISCREG_TBA);    PC = (TBA & ~mask(15)) |        (TL > 1 ? (1 << 14) : 0) |        ((TT << 5) & mask(14));    NPC = PC + sizeof(MachInst);}#if FULL_SYSTEMvoid SparcFaultBase::invoke(ThreadContext * tc){    //panic("Invoking a second fault!\n");    FaultBase::invoke(tc);    countStat()++;    //We can refer to this to see what the trap level -was-, but something    //in the middle could change it in the regfile out from under us.    MiscReg tl = tc->readMiscRegNoEffect(MISCREG_TL);    MiscReg tt = tc->readMiscRegNoEffect(MISCREG_TT);    MiscReg pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);    MiscReg hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);    Addr PC, NPC;    PrivilegeLevel current;    if (hpstate & HPSTATE::hpriv)        current = Hyperprivileged;    else if (pstate & PSTATE::priv)        current = Privileged;    else        current = User;    PrivilegeLevel level = getNextLevel(current);    if ((hpstate & HPSTATE::red) || (tl == MaxTL - 1)) {        getREDVector(5, PC, NPC);        doREDFault(tc, tt);        //This changes the hpstate and pstate, so we need to make sure we        //save the old version on the trap stack in doREDFault.        enterREDState(tc);    } else if (tl == MaxTL) {        panic("Should go to error state here.. crap\n");        //Do error_state somehow?        //Probably inject a WDR fault using the interrupt mechanism.        //What should the PC and NPC be set to?    } else if (tl > MaxPTL && level == Privileged) {        //guest_watchdog fault        doNormalFault(tc, trapType(), true);        getHyperVector(tc, PC, NPC, 2);    } else if (level == Hyperprivileged ||            level == Privileged && trapType() >= 384) {        doNormalFault(tc, trapType(), true);        getHyperVector(tc, PC, NPC, trapType());    } else {        doNormalFault(tc, trapType(), false);        getPrivVector(tc, PC, NPC, trapType(), tl+1);    }    tc->setPC(PC);    tc->setNextPC(NPC);    tc->setNextNPC(NPC + sizeof(MachInst));}void PowerOnReset::invoke(ThreadContext * tc){    //For SPARC, when a system is first started, there is a power    //on reset Trap which sets the processor into the following state.    //Bits that aren't set aren't defined on startup.    tc->setMiscRegNoEffect(MISCREG_TL, MaxTL);    tc->setMiscRegNoEffect(MISCREG_TT, trapType());    tc->setMiscReg(MISCREG_GL, MaxGL);    //Turn on pef and priv, set everything else to 0    tc->setMiscRegNoEffect(MISCREG_PSTATE, (1 << 4) | (1 << 2));    //Turn on red and hpriv, set everything else to 0    MiscReg HPSTATE = tc->readMiscRegNoEffect(MISCREG_HPSTATE);    //HPSTATE.red = 1    HPSTATE |= (1 << 5);    //HPSTATE.hpriv = 1    HPSTATE |= (1 << 2);    //HPSTATE.ibe = 0    HPSTATE &= ~(1 << 10);    //HPSTATE.tlz = 0    HPSTATE &= ~(1 << 0);    tc->setMiscRegNoEffect(MISCREG_HPSTATE, HPSTATE);    //The tick register is unreadable by nonprivileged software    tc->setMiscRegNoEffect(MISCREG_TICK, 1ULL << 63);    //Enter RED state. We do this last so that the actual state preserved in    //the trap stack is the state from before this fault.    enterREDState(tc);    Addr PC, NPC;    getREDVector(trapType(), PC, NPC);    tc->setPC(PC);    tc->setNextPC(NPC);    tc->setNextNPC(NPC + sizeof(MachInst));    //These registers are specified as "undefined" after a POR, and they    //should have reasonable values after the miscregfile is reset    /*    // Clear all the soft interrupt bits    softint = 0;    // disable timer compare interrupts, reset tick_cmpr    tc->setMiscRegNoEffect(MISCREG_    tick_cmprFields.int_dis = 1;    tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing    stickFields.npt = 1; //The TICK register is unreadable by by !priv    stick_cmprFields.int_dis = 1; // disable timer compare interrupts    stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing    tt[tl] = _trapType;    hintp = 0; // no interrupts pending    hstick_cmprFields.int_dis = 1; // disable timer compare interrupts    hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing    */}#else // !FULL_SYSTEMvoid FastInstructionAccessMMUMiss::invoke(ThreadContext *tc){    Process *p = tc->getProcessPtr();    TlbEntry entry;    bool success = p->pTable->lookup(vaddr, entry);    if(!success) {        panic("Tried to execute unmapped address %#x.\n", vaddr);    } else {        Addr alignedVaddr = p->pTable->pageAlign(vaddr);        tc->getITBPtr()->insert(alignedVaddr, 0 /*partition id*/,                p->M5_pid /*context id*/, false, entry.pte);    }}void FastDataAccessMMUMiss::invoke(ThreadContext *tc){    Process *p = tc->getProcessPtr();    TlbEntry entry;    bool success = p->pTable->lookup(vaddr, entry);    if(!success) {        p->checkAndAllocNextPage(vaddr);        success = p->pTable->lookup(vaddr, entry);    }    if(!success) {        panic("Tried to access unmapped address %#x.\n", vaddr);    } else {        Addr alignedVaddr = p->pTable->pageAlign(vaddr);        tc->getDTBPtr()->insert(alignedVaddr, 0 /*partition id*/,                p->M5_pid /*context id*/, false, entry.pte);    }}void SpillNNormal::invoke(ThreadContext *tc){    doNormalFault(tc, trapType(), false);    Process *p = tc->getProcessPtr();    //XXX This will only work in faults from a SparcLiveProcess    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);    assert(lp);    //Then adjust the PC and NPC    Addr spillStart = lp->readSpillStart();    tc->setPC(spillStart);    tc->setNextPC(spillStart + sizeof(MachInst));    tc->setNextNPC(spillStart + 2*sizeof(MachInst));}void FillNNormal::invoke(ThreadContext *tc){    doNormalFault(tc, trapType(), false);    Process * p = tc->getProcessPtr();    //XXX This will only work in faults from a SparcLiveProcess    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);    assert(lp);    //Then adjust the PC and NPC    Addr fillStart = lp->readFillStart();    tc->setPC(fillStart);    tc->setNextPC(fillStart + sizeof(MachInst));    tc->setNextNPC(fillStart + 2*sizeof(MachInst));}void TrapInstruction::invoke(ThreadContext *tc){    //In SE, this mechanism is how the process requests a service from the    //operating system. We'll get the process object from the thread context    //and let it service the request.    Process *p = tc->getProcessPtr();    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);    assert(lp);    lp->handleTrap(_n, tc);    //We need to explicitly advance the pc, since that's not done for us    //on a faulting instruction    tc->setPC(tc->readNextPC());    tc->setNextPC(tc->readNextNPC());    tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst));}#endif} // namespace SparcISA

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?