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:
committed by
Andrea Mondelli
parent
7bb690c1ee
commit
975fcf1355
@@ -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;
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -81,3 +81,9 @@ PMAChecker::isUncacheable(PacketPtr pkt)
|
||||
{
|
||||
return isUncacheable(pkt->getAddrRange());
|
||||
}
|
||||
|
||||
void
|
||||
PMAChecker::takeOverFrom(PMAChecker *old)
|
||||
{
|
||||
uncacheable = old->uncacheable;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -519,3 +519,9 @@ TLB::TlbStats::TlbStats(Stats::Group *parent)
|
||||
readAccesses + writeAccesses)
|
||||
{
|
||||
}
|
||||
|
||||
Port *
|
||||
TLB::getTableWalkerPort()
|
||||
{
|
||||
return &walker->getPort("port");
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user