Fix granularity control

This commit is contained in:
Samuel Lindemer 2021-05-27 15:50:45 +02:00
parent 6471014131
commit 4a2dc0ff5f
3 changed files with 42 additions and 45 deletions

View File

@ -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

View File

@ -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()

View File

@ -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