From 4a2dc0ff5f69894bd6daae67ea1385e5674fa5cd Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 27 May 2021 15:50:45 +0200 Subject: [PATCH] Fix granularity control --- .../scala/vexriscv/plugin/CsrPlugin.scala | 25 ++++++----- .../scala/vexriscv/plugin/PmpPlugin.scala | 19 ++++---- src/test/cpp/raw/pmp/src/crt.S | 43 +++++++++---------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 471ffe3..f8d944a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -344,13 +344,13 @@ case class CsrDuringWrite(doThat :() => Unit) case class CsrDuringRead(doThat :() => Unit) case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) -case class CsrAllow() -case class CsrMapping() extends CsrInterface{ +case class CsrMapping() extends Area with CsrInterface { val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() val always = ArrayBuffer[Any]() val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) + val allowCsrSignal = False val hazardFree = Bool() readDataSignal := readDataInit @@ -364,11 +364,11 @@ case class CsrMapping() extends CsrInterface{ override def during(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuring(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) override def duringAny(): Bool = ??? - override def duringAnyWrite(body: => Unit) : Unit = always += CsrDuringRead(() => body) - override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringWrite(() => body) + override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringRead(() => body) + override def duringAnyWrite(body: => Unit) : Unit = always += CsrDuringWrite(() => body) override def readData() = readDataSignal override def writeData() = writeDataSignal - override def allow(csrAddress: Int): Unit = addMappingAt(csrAddress, CsrAllow()) + override def allowCsr() = allowCsrSignal := True override def isHazardFree() = hazardFree } @@ -386,9 +386,9 @@ trait CsrInterface{ r(csrAddress,bitOffset,that) w(csrAddress,bitOffset,that) } - def allow(csrAddress: Int): Unit - def duringAnyWrite(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage - def duringAnyRead(body: => Unit) : Unit //same than above for read + def duringAnyRead(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage + def duringAnyWrite(body: => Unit) : Unit //same than above for read + def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -515,9 +515,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringRead(csrAddress)(body) override def during(csrAddress: Int)(body: => Unit): Unit = csrMapping.during(csrAddress)(body) override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) - override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) override def duringAnyRead(body: => Unit) = csrMapping.duringAnyRead(body) - override def allow(csrAddress: Int): Unit = csrMapping.allow(csrAddress) + override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) + override def allowCsr() = csrMapping.allowCsr() override def readData() = csrMapping.readData() override def writeData() = csrMapping.writeData() override def isHazardFree() = csrMapping.isHazardFree() @@ -1147,8 +1147,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readEnable = readInstruction && !arbitration.isStuck csrMapping.hazardFree := !blockedBySideEffects - val READDATASIGNAL = csrMapping.readDataSignal - val readToWriteData = CombInit(readData) writeData := (if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( False -> writeSrc, @@ -1183,7 +1181,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } else { if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE)) - if (jobs.exists(j => j.isInstanceOf[CsrAllow])) illegalAccess := False } @@ -1269,6 +1266,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep case element : CsrDuringRead => when(readInstruction){element.doThat()} } + illegalAccess clearWhen(csrMapping.allowCsrSignal) + when(privilege < csrAddress(9 downto 8).asUInt){ illegalAccess := True readInstruction := False diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index e10a92a..e6c94ea 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -11,7 +11,6 @@ import vexriscv.plugin.MemoryTranslatorPort.{_} import spinal.core._ import spinal.lib._ import spinal.lib.fsm._ -import javax.net.ssl.TrustManager /* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. * These section numbers contain flags which apply to regions defined by the @@ -79,15 +78,15 @@ trait Pmp { def lBit = 7 } -class PmpSetter(grain : Int) extends Component with Pmp { +class PmpSetter(cutoff : Int) extends Component with Pmp { val io = new Bundle { val addr = in UInt(xlen bits) - val base, mask = out UInt(xlen - grain bits) + val base, mask = out UInt(xlen - cutoff bits) } val ones = io.addr & ~(io.addr + 1) - io.base := io.addr(xlen - 1 - grain downto 0) ^ ones(xlen - 1 - grain downto 0) - io.mask := ~ones(xlen - grain downto 1) + io.base := io.addr(xlen - 3 downto cutoff - 2) ^ ones(xlen - 3 downto cutoff - 2) + io.mask := ~ones(xlen - 2 downto cutoff - 1) } case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) @@ -98,7 +97,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend var setter : PmpSetter = null var dPort, iPort : ProtectedMemoryTranslatorPort = null - val grain = log2Up(granularity) - 1 + val cutoff = log2Up(granularity) - 1 override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) @@ -110,7 +109,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } override def setup(pipeline: VexRiscv): Unit = { - setter = new PmpSetter(grain) + setter = new PmpSetter(cutoff) } override def build(pipeline: VexRiscv): Unit = { @@ -123,7 +122,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val pmpaddr = Mem(UInt(xlen bits), regions) val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init(0)) - val base, mask = Vector.fill(regions)(Reg(UInt(xlen - grain bits))) + val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) // object PMPCFG extends Stageable(Bool) // object PMPADDR extends Stageable(Bool) @@ -313,7 +312,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend dPort.bus.rsp.allowExecute := False dPort.bus.busy := False - val hits = getHits(address(31 downto grain)) + val hits = getHits(address(31 downto cutoff)) when(~hits.orR) { dPort.bus.rsp.allowRead := privilegeService.isMachine() @@ -335,7 +334,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend iPort.bus.rsp.allowWrite := False iPort.bus.busy := False - val hits = getHits(address(31 downto grain)) + val hits = getHits(address(31 downto cutoff)) when(~hits.orR) { iPort.bus.rsp.allowExecute := privilegeService.isMachine() diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S index a03e76c..3dd75ff 100644 --- a/src/test/cpp/raw/pmp/src/crt.S +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -8,15 +8,15 @@ #define TRAP_RETURN x30 #define TRAP_EXIT x9 -#define PMPCFG0 0x07120000 -#define PMPCFG0_ 0x07920808 +#define PMPCFG0 0x071a0000 +#define PMPCFG0_ 0x079a0808 #define PMPCFG1 0x191f0304 #define PMPCFG2 0x000f090a -#define PMPCFG3 0x0f1e1900 +#define PMPCFG3 0x1c1e1900 #define PMPADDR0 0x20000000 // OFF (test0) -> TOR (test1) -> OFF (test2) #define PMPADDR1 0xffffffff // OFF (test0) -> TOR (test1) -> OFF (test2) -#define PMPADDR2 0x20002000 // NA4 W +#define PMPADDR2 0x20200000 // NAPOT W #define PMPADDR3 0x20003fff // OFF RWX -> 0x00000000 OFF RWX (test2) #define PMPADDR4 0x20003fff // OFF X #define PMPADDR5 0x20003fff // OFF RW @@ -29,7 +29,7 @@ #define PMPADDR12 0x00000000 // OFF #define PMPADDR13 0x00000000 // NAPOT R #define PMPADDR14 0x00000000 // NAPOT WX -#define PMPADDR15 0x00000000 // TOR RWX +#define PMPADDR15 0x000001ff // NAPOT X .global _start _start: @@ -71,6 +71,8 @@ test0: csrw pmpcfg1, x5 li x5, PMPCFG2 csrw pmpcfg2, x5 + csrr x6, pmpcfg2 + bne x5, x6, fail li x5, PMPCFG3 csrw pmpcfg3, x5 li x5, PMPADDR0 @@ -125,11 +127,11 @@ test1: csrw pmpcfg0, x5 // lock region 2 csrr x6, pmpcfg0 bne x5, x6, fail - li x1, 0x80008000 + li x1, 0x80800000 li x2, 0xdeadbeef - sw x2, 0x0(x1) // should be OK (write 0x80008000) + sw x2, 0x0(x1) // should be OK (write 0x80800000) la TRAP_RETURN, test2 - lw x3, 0x0(x1) // should fault (read 0x80008000) + lw x3, 0x0(x1) // should fault (read 0x80800000) j fail // "unlock" region 2, attempt read/write from machine mode @@ -140,21 +142,17 @@ test2: csrw pmpcfg0, x5 // "unlock" region 2 csrr x6, pmpcfg0 beq x5, x6, fail - li x5, PMPADDR3 csrwi pmpaddr3, 0x0 csrr x6, pmpaddr3 - bnez x6, fail - beq x5, x6, fail - li x5, PMPADDR2 + bnez x6, fail csrwi pmpaddr2, 0x0 csrr x6, pmpaddr2 - beqz x6, fail - bne x5, x6, fail - li x1, 0x80008000 + beqz x6, fail + li x1, 0x80800000 li x2, 0xdeadbeef - sw x2, 0x0(x1) // should still be OK (write 0x80008000) + sw x2, 0x0(x1) // should still be OK (write 0x80800000) la TRAP_RETURN, test3 - lw x3, 0x0(x1) // should still fault (read 0x80008000) + lw x3, 0x0(x1) // should still fault (read 0x80800000) j fail // verify masked CSR read/write operations @@ -178,12 +176,12 @@ test3: li x5, 0x00ff00ff csrc pmpcfg0, x5 csrr x6, pmpcfg0 - li x5, 0x07920000 + li x5, 0x079a0000 bne x5, x6, fail li x5, 0x00ff0707 csrs pmpcfg0, x5 csrr x6, pmpcfg0 - li x5, 0x07920707 + li x5, 0x079a0707 bne x5, x6, fail // jump into user mode @@ -192,6 +190,7 @@ test4: la TRAP_RETURN, fail la x2, test5 csrw mepc, x2 + # j pass mret // attempt to read/write region 2 from user mode @@ -199,10 +198,10 @@ test5: li TEST_ID, 5 la TRAP_RETURN, fail li x2, 0xdeadbeef - li x1, 0x80008000 - sw x2, 0x0(x1) // should be OK (write 0x80008000) + li x1, 0x80800000 + sw x2, 0x0(x1) // should be OK (write 0x80800000) la TRAP_RETURN, test6 - lw x3, 0x0(x1) // should fault (read 0x80008000) + lw x3, 0x0(x1) // should fault (read 0x80800000) j fail // attempt to read/write other regions from user mode