From: Cui Jin Date: Wed, 13 Jan 2021 08:00:50 +0000 (+0800) Subject: arch-riscv: fix unintentionally CSR bit overwritten in different mode X-Git-Tag: develop-gem5-snapshot~192 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b1d7c8e77b4dda39f2e97e52182ff3f612055b11;p=gem5.git arch-riscv: fix unintentionally CSR bit overwritten in different mode Some CSR register is physically shared between different privilige level. Current implementation of CSR setting only considers to verify the bits visable in current privilige level, and directly writes the masked bits back to register. This leads to other bits invisable to current mode is overwritten and wrong behavior across the modes. Thus, CSR updating should always keep the bits value for other modes. e.g. disabling interrupt in S mode with setting SSTATUS SIE bit will lead to clear MIE bit as well (the interrupt is disabled unintentionally). All CSR register sharing same physical register in different mode may have similar issue. I only fixed some important ones. The fix is verified in FS. Jira Issue: https://gem5.atlassian.net/browse/GEM5-860 Change-Id: I34d4766a4b483b5add2c3bbefd28b21b9abf37f6 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/39036 Tested-by: kokoro Reviewed-by: Ayaz Akram Maintainer: Jason Lowe-Power --- diff --git a/src/arch/riscv/isa/formats/standard.isa b/src/arch/riscv/isa/formats/standard.isa index a32326f8f..4ed35c907 100644 --- a/src/arch/riscv/isa/formats/standard.isa +++ b/src/arch/riscv/isa/formats/standard.isa @@ -356,6 +356,7 @@ def template CSRExecute {{ break; } auto mask = CSRMasks.find(csr); + auto olddata_all = olddata; if (mask != CSRMasks.end()) olddata &= mask->second; DPRINTF(RiscvMisc, "Reading CSR %s: %#x\n", CSRData.at(csr).name, @@ -374,23 +375,32 @@ def template CSRExecute {{ fault = std::make_shared( error, machInst); } else { - DPRINTF(RiscvMisc, "Writing %#x to CSR %s.\n", data, + auto newdata_all = data; + if (mask != CSRMasks.end()) { + // we must keep those original bits not in mask + // olddata and data only contain thebits visable + // in current privilige level + newdata_all = (olddata_all & (~mask->second)) + | data; + } + DPRINTF(RiscvMisc, "Writing %#x to CSR %s.\n", + newdata_all, CSRData.at(csr).name); - INTERRUPT oldinterrupt = olddata; - INTERRUPT newinterrupt = data; switch (csr) { case CSR_FCSR: xc->setMiscReg(MISCREG_FFLAGS, bits(data, 4, 0)); xc->setMiscReg(MISCREG_FRM, bits(data, 7, 5)); break; case CSR_MIP: case CSR_MIE: - if (oldinterrupt.mei != newinterrupt.mei || - oldinterrupt.mti != newinterrupt.mti || - oldinterrupt.msi != newinterrupt.msi) { - xc->setMiscReg(CSRData.at(csr).physIndex,data); + case CSR_SIP: case CSR_SIE: + case CSR_UIP: case CSR_UIE: + case CSR_MSTATUS: case CSR_SSTATUS: case CSR_USTATUS: + if (newdata_all != olddata_all) { + xc->setMiscReg(CSRData.at(csr).physIndex, + newdata_all); } else { - std::string error = "Interrupt m bits are " - "read-only\n"; + std::string error = "Only bits in mask are " + "allowed to be set\n"; fault = std::make_shared( error, machInst); }