arch-riscv: Fixed CPU switching and PLIC issue with MinorCPU

Added takeover methods for PMA Checker and RiscvTLB to ensure
that checkpoint restoration works. Also added logic in PLIC
to prevent posting interrupts to a CPU that has yet to complete
the current interrupt. PLIC's behaviour when a CPU claims another
interrupt before completion is also changed. Now PLIC will return
the uncompleted interrupt ID instead of return 0. This behaviour
is not documented in the specs but is designed this way to avoid
issues from CPU side (especially MinorCPU).

Change-Id: I68eaaf56d2c4d76cc1e0a1e2160f5abe184c2cd5
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/41933
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ayaz Akram <yazakram@ucdavis.edu>
This commit is contained in:
Peter Yuen
2021-02-26 15:43:50 +07:00
committed by Andrea Mondelli
parent 7bb690c1ee
commit 975fcf1355
9 changed files with 67 additions and 13 deletions

View File

@@ -103,7 +103,7 @@ class BaseMMU : public SimObject
return getTlb(mode)->finalizePhysical(req, tc, mode);
}
void takeOverFrom(BaseMMU *old_mmu);
virtual void takeOverFrom(BaseMMU *old_mmu);
public:
BaseTLB* dtb;

View File

@@ -35,6 +35,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.objects.BaseMMU import BaseMMU
from m5.objects.RiscvTLB import RiscvTLB
from m5.objects.PMAChecker import PMAChecker
@@ -45,7 +47,7 @@ class RiscvMMU(BaseMMU):
cxx_header = 'arch/riscv/mmu.hh'
itb = RiscvTLB()
dtb = RiscvTLB()
pma_checker = PMAChecker()
pma_checker = Param.PMAChecker(PMAChecker(), "PMA Checker")
@classmethod
def walkerPorts(cls):

View File

@@ -43,7 +43,7 @@ class RiscvPagetableWalker(ClockedObject):
num_squash_per_cycle = Param.Unsigned(4,
"Number of outstanding walks that can be squashed per cycle")
# Grab the pma_checker from the MMU
pma_checker = Param.PMAChecker(Parent.any, "PMA Chekcer")
pma_checker = Param.PMAChecker(Parent.any, "PMA Checker")
class RiscvTLB(BaseTLB):
type = 'RiscvTLB'
@@ -53,4 +53,4 @@ class RiscvTLB(BaseTLB):
walker = Param.RiscvPagetableWalker(\
RiscvPagetableWalker(), "page table walker")
# Grab the pma_checker from the MMU
pma_checker = Param.PMAChecker(Parent.any, "PMA Chekcer")
pma_checker = Param.PMAChecker(Parent.any, "PMA Checker")

View File

@@ -40,6 +40,7 @@
#include "arch/generic/mmu.hh"
#include "arch/riscv/isa.hh"
#include "arch/riscv/pma_checker.hh"
#include "arch/riscv/tlb.hh"
#include "params/RiscvMMU.hh"
@@ -49,8 +50,10 @@ namespace RiscvISA {
class MMU : public BaseMMU
{
public:
PMAChecker *pma;
MMU(const RiscvMMUParams &p)
: BaseMMU(p)
: BaseMMU(p), pma(p.pma_checker)
{}
PrivilegeMode
@@ -64,6 +67,14 @@ class MMU : public BaseMMU
{
return static_cast<TLB*>(dtb)->getWalker();
}
void
takeOverFrom(BaseMMU *old_mmu) override
{
MMU *ommu = dynamic_cast<MMU*>(old_mmu);
BaseMMU::takeOverFrom(ommu);
pma->takeOverFrom(ommu->pma);
}
};
} // namespace RiscvISA

View File

@@ -81,3 +81,9 @@ PMAChecker::isUncacheable(PacketPtr pkt)
{
return isUncacheable(pkt->getAddrRange());
}
void
PMAChecker::takeOverFrom(PMAChecker *old)
{
uncacheable = old->uncacheable;
}

View File

@@ -74,6 +74,8 @@ class PMAChecker : public SimObject
bool isUncacheable(const AddrRange &range);
bool isUncacheable(const Addr &addr, const unsigned size);
bool isUncacheable(PacketPtr pkt);
void takeOverFrom(PMAChecker *old);
};
#endif // __ARCH_RISCV_PMA_CHECKER_HH__

View File

@@ -519,3 +519,9 @@ TLB::TlbStats::TlbStats(Stats::Group *parent)
readAccesses + writeAccesses)
{
}
Port *
TLB::getTableWalkerPort()
{
return &walker->getPort("port");
}

View File

@@ -92,7 +92,7 @@ class TLB : public BaseTLB
Walker *getWalker();
void takeOverFrom(BaseTLB *otlb) override {}
void takeOverFrom(BaseTLB *old) override {}
TlbEntry *insert(Addr vpn, const TlbEntry &entry);
void flushAll() override;
@@ -108,6 +108,18 @@ class TLB : public BaseTLB
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
/**
* Get the table walker port. This is used for
* migrating port connections during a CPU takeOverFrom()
* call. For architectures that do not have a table walker,
* NULL is returned, hence the use of a pointer rather than a
* reference. For RISC-V this method will always return a valid
* port pointer.
*
* @return A pointer to the walker port
*/
Port *getTableWalkerPort() override;
Addr translateWithTLB(Addr vaddr, uint16_t asid, Mode mode);
Fault translateAtomic(const RequestPtr &req,

View File

@@ -354,17 +354,18 @@ Plic::readClaim(Register32& reg, const int context_id)
context_id, max_int_id);
clear(max_int_id);
reg.update(max_int_id);
return reg.get();
} else {
DPRINTF(Plic,
"Claim already cleared - context: %d, interrupt ID: %d\n",
context_id, max_int_id);
reg.update(0);
return 0;
}
} else {
warn("PLIC claim failed (not completed) - context: %d", context_id);
reg.update(0);
warn("PLIC claim repeated (not completed) - context: %d, last: %d",
context_id, lastID[context_id]);
return lastID[context_id];
}
return reg.get();
}
void
@@ -381,6 +382,7 @@ Plic::writeClaim(Register32& reg, const uint32_t& data, const int context_id)
DPRINTF(Plic,
"Complete - context: %d, interrupt ID: %d\n",
context_id, reg.get());
updateInt();
}
void
@@ -445,11 +447,11 @@ Plic::updateInt()
uint32_t max_id = output.maxID[i];
uint32_t priority = output.maxPriority[i];
uint32_t threshold = registers.threshold[i].get();
if (priority > threshold && max_id > 0) {
if (priority > threshold && max_id > 0 && lastID[i] == 0) {
DPRINTF(Plic,
"Int posted - thread: %d, int id: %d, ",
thread_id, int_id);
DPRINTF(Plic,
DPRINTFR(Plic,
"pri: %d, thres: %d\n", priority, threshold);
intrctrl->post(thread_id, int_id, 0);
} else {
@@ -457,7 +459,7 @@ Plic::updateInt()
DPRINTF(Plic,
"Int filtered - thread: %d, int id: %d, ",
thread_id, int_id);
DPRINTF(Plic,
DPRINTFR(Plic,
"pri: %d, thres: %d\n", priority, threshold);
}
intrctrl->clear(thread_id, int_id, 0);
@@ -499,6 +501,12 @@ Plic::serialize(CheckpointOut &cp) const
SERIALIZE_SCALAR(n_outputs);
SERIALIZE_CONTAINER(output.maxID);
SERIALIZE_CONTAINER(output.maxPriority);
SERIALIZE_CONTAINER(pendingPriority);
for (int i=0; i < effPriority.size(); i++) {
arrayParamOut(cp, std::string("effPriority") +
std::to_string(i), effPriority[i]);
}
SERIALIZE_CONTAINER(lastID);
}
void
@@ -541,4 +549,11 @@ Plic::unserialize(CheckpointIn &cp)
}
UNSERIALIZE_CONTAINER(output.maxID);
UNSERIALIZE_CONTAINER(output.maxPriority);
UNSERIALIZE_CONTAINER(pendingPriority);
for (int i=0; i < effPriority.size(); i++) {
arrayParamIn(cp, std::string("effPriority") +
std::to_string(i), effPriority[i]);
}
UNSERIALIZE_CONTAINER(lastID);
updateInt();
}