From 524c85e37feec0f555d7acb9faa22fce81e714c4 Mon Sep 17 00:00:00 2001 From: kajoljain379 Date: Wed, 16 Jan 2019 17:09:56 +0530 Subject: [PATCH] arch-power: Added Data and Instruction Interrupt Handler Added data and instruction storage interrupr handler and modify radixwalk.cc to check permissions and privileges of both data and instrustion. Change-Id: I5d3a820862cde7bd298f0b715777f069fb1e39d1 Signed-off-by: kajoljain379 --- src/arch/power/faults.hh | 90 +++++++++++++++++++++++++++++++++++++ src/arch/power/radixwalk.cc | 76 +++++++++++++++++++++---------- src/arch/power/radixwalk.hh | 8 ++-- 3 files changed, 148 insertions(+), 26 deletions(-) diff --git a/src/arch/power/faults.hh b/src/arch/power/faults.hh index 29a057154..3f193578c 100644 --- a/src/arch/power/faults.hh +++ b/src/arch/power/faults.hh @@ -139,6 +139,96 @@ class PowerInterrupt : public PowerFaultBase } }; +class InstrStorageInterrupt : public PowerInterrupt +{ +public: + InstrStorageInterrupt() + { + } + virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr , uint64_t bitSet = 0) + { + tc->setIntReg(INTREG_SRR0 , tc->instAddr()); + PowerInterrupt::updateSRR1(tc, bitSet); + PowerInterrupt::updateMsr(tc); + tc->pcState(InstrStoragePCSet); + } +}; + +class InstrInvalidInterrupt : public InstrStorageInterrupt +{ +public: + InstrInvalidInterrupt() + { + } + virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr) + { + InstrStorageInterrupt::invoke(tc, inst ,setBitMask(INVALID_SET_BIT)); + } +}; + +//When permissions or privilege violates +class InstrPriStorageInterrupt : public InstrStorageInterrupt +{ +public: + InstrPriStorageInterrupt() + { + } + virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr) + { + InstrStorageInterrupt::invoke(tc, inst ,setBitMask(PERMISSION_BIT)); + } +}; + +class DataStorageInterrupt :public PowerInterrupt +{ +public: + DataStorageInterrupt() + { + } + virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr ,uint64_t bitSet = 0) + { + Msr msr = tc->readIntReg(INTREG_MSR); + tc->setIntReg(INTREG_SRR0 , tc->instAddr()); + PowerInterrupt::updateSRR1(tc, 0); + uint64_t dsisr = tc->readIntReg(INTREG_DSISR); + dsisr = (dsisr & DSISR_MASK) | bitSet; + if (msr.dr) + dsisr = setbit(33, dsisr); + tc->setIntReg(INTREG_DSISR, dsisr); + PowerInterrupt::updateMsr(tc); + tc->pcState(DataStoragePCSet); + } +}; + +class DataInvalidInterrupt : public DataStorageInterrupt +{ +public: + DataInvalidInterrupt() + { + } + virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr) + { + DataStorageInterrupt::invoke(tc, inst ,setBitMask(INVALID_SET_BIT)); + } +}; + +//When permissions or privilege violates +class DataPriStorageInterrupt : public DataStorageInterrupt +{ +public: + DataPriStorageInterrupt() + { + } + virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr) + { + DataStorageInterrupt::invoke(tc, inst ,setBitMask(PERMISSION_BIT)); + } }; //TODO: Need to add Floating point and TM Bad thing fault handler diff --git a/src/arch/power/radixwalk.cc b/src/arch/power/radixwalk.cc index 04457960e..7bc671684 100644 --- a/src/arch/power/radixwalk.cc +++ b/src/arch/power/radixwalk.cc @@ -135,17 +135,24 @@ RadixWalk::start(ThreadContext * tc, RequestPtr req, BaseTLB::Mode mode) DPRINTF(RadixWalk,"RPDB: 0x%lx\n RPDS: 0x%lx\n usefulBits: %ld\n\n" ,rpdb,rpds,usefulBits); - //TODO: - //========== - // Fault should be generated as a return value of walkTree. Perhaps - // we can pass paddr as a pointer in which the physical address can - // be returned. - // As of now we assume that there are no faults. - Addr paddr = this->walkTree(vaddr, nextLevelBase, + std::pair AddrTran; + + Lpcr lpcr = tc->readIntReg(INTREG_LPCR); + + if (lpcr.hr == 0 && lpcr.vc <= 3) { + if (mode == BaseTLB::Execute) + return std::make_shared(); + + return std::make_shared(); + } + AddrTran = this->walkTree(vaddr, nextLevelBase, tc, mode, nextLevelSize, usefulBits); - req->setPaddr(paddr); - DPRINTF(RadixWalk,"Radix Translated %#x -> %#x\n",vaddr,paddr); - return NoFault; + if (AddrTran.first) { + req->setPaddr(AddrTran.first); + DPRINTF(RadixWalk,"Radix Translated %#x -> %#x\n", + vaddr,AddrTran.first); + } + return AddrTran.second; } uint64_t @@ -303,12 +310,11 @@ RadixWalk::getRPDEntry(ThreadContext * tc, Addr vaddr) return prte0; } -Addr -RadixWalk::walkTree(Addr vaddr ,uint64_t curBase , - uint64_t curSize ,uint64_t usefulBits) +std::pair +RadixWalk::walkTree(Addr vaddr ,uint64_t curBase ,ThreadContext * tc , + BaseTLB::Mode mode ,uint64_t curSize ,uint64_t usefulBits) { uint64_t dataSize = 8; - if (curSize < 5) { panic("vaddr = %lx, Radix RPDS = %lx,is less than 5\n", vaddr, curSize); @@ -384,19 +390,42 @@ RadixWalk::walkTree(Addr vaddr ,uint64_t curBase , Rpde rpde = this->readPhysMem(entryAddr, dataSize); DPRINTF(RadixWalk,"rpde:%lx\n",(uint64_t)rpde); usefulBits = usefulBits - curSize; + std::pair AddrTran; + + if (rpde.valid == 0) { + AddrTran.first = vaddr; + if (mode == BaseTLB::Execute) + AddrTran.second = std::make_shared(); + else + AddrTran.second = std::make_shared(); + return AddrTran; + } + //Ref: Power ISA Manual v3.0B, Book-III, section 5.7.10.2 - if (rpde.leaf == 1) - { + if (rpde.leaf == 1) { + Rpte rpte = (uint64_t)rpde; uint64_t realpn = rpde & RPN_MASK; uint64_t pageMask = (1UL << usefulBits) - 1; Addr paddr = (realpn & ~pageMask) | (vaddr & pageMask); - - //TODO: Check for permissions. - // We aren't doing that right now - // If there is a mismatch in the permissions, - // generate a fault. DPRINTF(RadixWalk,"paddr:%lx\n",paddr); - return paddr; + AddrTran.second = NoFault; + AddrTran.first = paddr; + Msr msr = tc->readIntReg(INTREG_MSR); + + //Conditions for checking privileges and permissions + if (mode == BaseTLB::Execute && + (!rpte.exe || ( rpte.pri && msr.pr ))) { + AddrTran.second = std::make_shared(); + } + + else if ( ( mode == BaseTLB::Read && !rpte.read ) || + ( mode == BaseTLB::Write && !rpte.r_w ) || + (( mode != BaseTLB::Execute) + && (rpte.pri && msr.pr ))) { + AddrTran.second = std::make_shared(); + } + + return AddrTran; } uint64_t nextLevelBase = align(rpde.NLB, DIR_BASE_ALIGN); @@ -404,7 +433,8 @@ RadixWalk::walkTree(Addr vaddr ,uint64_t curBase , DPRINTF(RadixWalk,"NLB: %lx\n",(uint64_t)nextLevelBase); DPRINTF(RadixWalk,"NLS: %lx\n",(uint64_t)nextLevelSize); DPRINTF(RadixWalk,"usefulBits: %lx",(uint64_t)usefulBits); - return walkTree(vaddr, nextLevelBase, nextLevelSize, usefulBits); + return walkTree(vaddr, nextLevelBase, tc , + mode, nextLevelSize, usefulBits); } void diff --git a/src/arch/power/radixwalk.hh b/src/arch/power/radixwalk.hh index 11814e0f1..8c9cd3813 100644 --- a/src/arch/power/radixwalk.hh +++ b/src/arch/power/radixwalk.hh @@ -64,9 +64,11 @@ namespace PowerISA Fault start(ThreadContext * _tc, RequestPtr req, BaseTLB::Mode mode); BaseMasterPort &getMasterPort(const std::string &if_name, PortID idx = InvalidPortID); - Addr getRPDEntry(ThreadContext * tc, Addr vaddr); - Addr walkTree(Addr vaddr ,uint64_t ptbase , - uint64_t ptsize ,uint64_t psize); + + Addr getRPDEntry(ThreadContext * tc, Addr vaddr); + std::pair walkTree(Addr vaddr ,uint64_t curBase , + ThreadContext * tc ,BaseTLB::Mode mode , + uint64_t curSize ,uint64_t usefulBits); typedef PowerRadixWalkParams Params; -- 2.30.2