Merge pull request #147 from lindemer/pmp

Physical Memory Protection (PMP) plugin
This commit is contained in:
Dolu1990 2020-12-11 15:22:28 +01:00 committed by GitHub
commit d2855fcfca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 859 additions and 9 deletions

View File

@ -0,0 +1,86 @@
package vexriscv.demo
import vexriscv.plugin._
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
import vexriscv.{plugin, VexRiscv, VexRiscvConfig}
import spinal.core._
object GenSecure extends App {
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new IBusCachedPlugin(
resetVector = 0x80000000l,
prediction = STATIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
)
),
new DBusCachedPlugin(
config = new DataCacheConfig(
cacheSize = 4096,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true
)
),
new PmpPlugin(
regions = 16,
ioRange = _(31 downto 28) === 0xf
),
new DecoderSimplePlugin(
catchIllegalInstruction = true
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = false
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false,
executeInsertion = true
),
new FullBarrelShifterPlugin,
new HazardSimplePlugin(
bypassExecute = true,
bypassMemory = true,
bypassWriteBack = true,
bypassWriteBackBuffer = true,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
),
new MulDivIterativePlugin(
genMul = true,
genDiv = true,
mulUnrollFactor = 1,
divUnrollFactor = 1
),
new CsrPlugin(CsrPluginConfig.secure(0x00000020l)),
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)
)
)
SpinalVerilog(cpu())
}

View File

@ -264,6 +264,31 @@ object CsrPluginConfig{
uinstretAccess = CsrAccess.NONE
)
def secure(mtvecInit : BigInt) = CsrPluginConfig(
catchIllegalAccess = true,
mvendorid = 1,
marchid = 2,
mimpid = 3,
mhartid = 0,
misaExtensionsInit = 0x101064, // RV32GCFMU
misaAccess = CsrAccess.READ_WRITE,
mtvecAccess = CsrAccess.READ_WRITE,
mtvecInit = mtvecInit,
mepcAccess = CsrAccess.READ_WRITE,
mscratchGen = true,
mcauseAccess = CsrAccess.READ_WRITE,
mbadaddrAccess = CsrAccess.READ_WRITE,
mcycleAccess = CsrAccess.READ_WRITE,
minstretAccess = CsrAccess.READ_WRITE,
ucycleAccess = CsrAccess.READ_ONLY,
uinstretAccess = CsrAccess.READ_ONLY,
wfiGenAsWait = true,
ecallGen = true,
userGen = true,
medelegAccess = CsrAccess.READ_WRITE,
midelegAccess = CsrAccess.READ_WRITE
)
}
case class CsrWrite(that : Data, bitOffset : Int)
case class CsrRead(that : Data , bitOffset : Int)

View File

@ -0,0 +1,216 @@
/*
* Copyright (c) 2020 Samuel Lindemer <samuel.lindemer@ri.se>
*
* SPDX-License-Identifier: MIT
*/
package vexriscv.plugin
import vexriscv.{VexRiscv, _}
import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections.
* These section numbers contain flags which apply to regions defined by the
* corresponding pmpaddr# register.
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg | pmpcfg0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmpcfg2
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 7 6 5 4 3 2 1 0
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | L | 0 | A | X | W | R | pmp#cfg
* +-------+-------+-------+-------+-------+-------+-------+-------+
*
* L: locks configuration until system reset (including M-mode)
* 0: hardwired to zero
* A: 0 = OFF (null region / disabled)
* 1 = TOR (top of range)
* 2 = NA4 (naturally aligned four-byte region)
* 3 = NAPOT (naturally aligned power-of-two region, > 7 bytes)
* X: execute
* W: write
* R: read
*
* TOR: Each 32-bit pmpaddr# register defines the upper bound of the pmp region
* right-shifted by two bits. The lower bound of the region is the previous
* pmpaddr# register. In the case of pmpaddr0, the lower bound is address 0x0.
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | address[33:2] | pmpaddr#
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* NAPOT: Each 32-bit pmpaddr# register defines the region address and the size
* of the pmp region. The number of concurrent 1s begging at the LSB indicates
* the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 =
* 16-byte, 0x...11 = 32-byte, etc.).
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | address[33:2] |0|1|1|1|1| pmpaddr#
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* NA4: This is essentially an edge case of NAPOT where the entire pmpaddr#
* register defines a 4-byte wide region.
*/
case class PmpRegister(previous : PmpRegister) extends Area {
def OFF = 0
def TOR = 1
def NA4 = 2
def NAPOT = 3
// Software-accessible CSR interface
val csr = new Area {
val r, w, x = Reg(Bool)
val l = RegInit(False)
val a = Reg(UInt(2 bits)) init(0)
val addr = Reg(UInt(32 bits))
}
// Active region bounds and permissions (internal)
val region = new Area {
val r, w, x = Reg(Bool)
val l, valid = RegInit(False)
val start, end = Reg(UInt(32 bits))
}
when(~region.l) {
region.r := csr.r
region.w := csr.w
region.x := csr.x
region.l := csr.l
val shifted = csr.addr |<< 2
region.valid := True
switch(csr.a) {
is(TOR) {
if (previous == null) {
region.start := 0
} else {
region.start := previous.region.end
}
if (csr.l == True) {
previous.region.l := True
}
region.end := shifted
}
is(NA4) {
region.start := shifted
region.end := shifted + 4
}
is(NAPOT) {
val mask = csr.addr & ~(csr.addr + 1)
val masked = (csr.addr & ~mask) |<< 2
region.start := masked
region.end := masked + ((mask + 1) |<< 3)
}
default {
region.end := shifted
region.valid := False
}
}
}
}
case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus)
class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator {
// Each pmpcfg# CSR configures four regions.
assert((regions % 4) == 0)
val pmps = ArrayBuffer[PmpRegister]()
val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]()
override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = {
val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus())
portsInfo += port
port.bus
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline._
import Riscv._
val csrService = pipeline.service(classOf[CsrInterface])
val privilegeService = pipeline.service(classOf[PrivilegeService])
val core = pipeline plug new Area {
// Instantiate pmpaddr0 ... pmpaddr# CSRs.
for (i <- 0 until regions) {
if (i == 0) {
pmps += PmpRegister(null)
} else {
pmps += PmpRegister(pmps.last)
}
csrService.rw(0x3b0 + i, pmps(i).csr.addr)
}
// Instantiate pmpcfg0 ... pmpcfg# CSRs.
for (i <- 0 until (regions / 4)) {
csrService.rw(0x3a0 + i,
31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l,
15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l,
27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x,
25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r,
19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x,
17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r,
11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x,
9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r,
3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x,
1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r
)
}
// Connect memory ports to PMP logic.
val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area {
val address = port.bus.cmd.virtualAddress
port.bus.rsp.physicalAddress := address
// Only the first matching PMP region applies.
val hits = pmps.map(pmp => pmp.region.valid &&
pmp.region.start <= address &&
pmp.region.end > address &&
(pmp.region.l || ~privilegeService.isMachine()))
// M-mode has full access by default, others have none.
when(CountOne(hits) === 0) {
port.bus.rsp.allowRead := privilegeService.isMachine()
port.bus.rsp.allowWrite := privilegeService.isMachine()
port.bus.rsp.allowExecute := privilegeService.isMachine()
} otherwise {
port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.region.r))
port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.region.w))
port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.region.x))
}
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
port.bus.rsp.exception := False
port.bus.rsp.refilling := False
port.bus.busy := False
}
}
}
}

View File

@ -0,0 +1,192 @@
build/pmp.elf: file format elf32-littleriscv
Disassembly of section .crt_section:
80000000 <_start>:
80000000: 00000097 auipc ra,0x0
80000004: 01008093 addi ra,ra,16 # 80000010 <trap>
80000008: 30509073 csrw mtvec,ra
8000000c: 00c0006f j 80000018 <test0>
80000010 <trap>:
80000010: 341f1073 csrw mepc,t5
80000014: 30200073 mret
80000018 <test0>:
80000018: 00000e13 li t3,0
8000001c: 00000f17 auipc t5,0x0
80000020: 250f0f13 addi t5,t5,592 # 8000026c <fail>
80000024: 800000b7 lui ra,0x80000
80000028: 80008237 lui tp,0x80008
8000002c: deadc137 lui sp,0xdeadc
80000030: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc77>
80000034: 0020a023 sw sp,0(ra) # 80000000 <pass+0xfffffd88>
80000038: 00222023 sw sp,0(tp) # 80008000 <pass+0x7d88>
8000003c: 0000a183 lw gp,0(ra)
80000040: 22311663 bne sp,gp,8000026c <fail>
80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000>
80000048: 22311263 bne sp,gp,8000026c <fail>
8000004c: 071202b7 lui t0,0x7120
80000050: 3a029073 csrw pmpcfg0,t0
80000054: 191f02b7 lui t0,0x191f0
80000058: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc>
8000005c: 3a129073 csrw pmpcfg1,t0
80000060: 000f02b7 lui t0,0xf0
80000064: 50628293 addi t0,t0,1286 # f0506 <_start-0x7ff0fafa>
80000068: 3a229073 csrw pmpcfg2,t0
8000006c: 0f1e22b7 lui t0,0xf1e2
80000070: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700>
80000074: 3a329073 csrw pmpcfg3,t0
80000078: 200002b7 lui t0,0x20000
8000007c: 3b029073 csrw pmpaddr0,t0
80000080: fff00293 li t0,-1
80000084: 3b129073 csrw pmpaddr1,t0
80000088: 200022b7 lui t0,0x20002
8000008c: 3b229073 csrw pmpaddr2,t0
80000090: 200042b7 lui t0,0x20004
80000094: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001>
80000098: 3b329073 csrw pmpaddr3,t0
8000009c: 200042b7 lui t0,0x20004
800000a0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001>
800000a4: 3b429073 csrw pmpaddr4,t0
800000a8: 200042b7 lui t0,0x20004
800000ac: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001>
800000b0: 3b529073 csrw pmpaddr5,t0
800000b4: 200022b7 lui t0,0x20002
800000b8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001>
800000bc: 3b629073 csrw pmpaddr6,t0
800000c0: 200062b7 lui t0,0x20006
800000c4: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001>
800000c8: 3b729073 csrw pmpaddr7,t0
800000cc: 2000c2b7 lui t0,0x2000c
800000d0: 3b829073 csrw pmpaddr8,t0
800000d4: 2000d2b7 lui t0,0x2000d
800000d8: 3b929073 csrw pmpaddr9,t0
800000dc: fff00293 li t0,-1
800000e0: 3ba29073 csrw pmpaddr10,t0
800000e4: 00000293 li t0,0
800000e8: 3bb29073 csrw pmpaddr11,t0
800000ec: 00000293 li t0,0
800000f0: 3bc29073 csrw pmpaddr12,t0
800000f4: 00000293 li t0,0
800000f8: 3bd29073 csrw pmpaddr13,t0
800000fc: 00000293 li t0,0
80000100: 3be29073 csrw pmpaddr14,t0
80000104: 00000293 li t0,0
80000108: 3bf29073 csrw pmpaddr15,t0
8000010c: 00c10137 lui sp,0xc10
80000110: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012>
80000114: 0020a023 sw sp,0(ra)
80000118: 00222023 sw sp,0(tp) # 0 <_start-0x80000000>
8000011c: 0000a183 lw gp,0(ra)
80000120: 14311663 bne sp,gp,8000026c <fail>
80000124: 00000193 li gp,0
80000128: 00022183 lw gp,0(tp) # 0 <_start-0x80000000>
8000012c: 14311063 bne sp,gp,8000026c <fail>
80000130 <test1>:
80000130: 00100e13 li t3,1
80000134: 00000f17 auipc t5,0x0
80000138: 138f0f13 addi t5,t5,312 # 8000026c <fail>
8000013c: 079212b7 lui t0,0x7921
80000140: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8>
80000144: 3a029073 csrw pmpcfg0,t0
80000148: 800080b7 lui ra,0x80008
8000014c: deadc137 lui sp,0xdeadc
80000150: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc77>
80000154: 0020a023 sw sp,0(ra) # 80008000 <pass+0x7d88>
80000158: 00000f17 auipc t5,0x0
8000015c: 010f0f13 addi t5,t5,16 # 80000168 <test2>
80000160: 0000a183 lw gp,0(ra)
80000164: 1080006f j 8000026c <fail>
80000168 <test2>:
80000168: 00200e13 li t3,2
8000016c: 00000f17 auipc t5,0x0
80000170: 100f0f13 addi t5,t5,256 # 8000026c <fail>
80000174: 071202b7 lui t0,0x7120
80000178: 3a029073 csrw pmpcfg0,t0
8000017c: 800080b7 lui ra,0x80008
80000180: deadc137 lui sp,0xdeadc
80000184: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc77>
80000188: 0020a023 sw sp,0(ra) # 80008000 <pass+0x7d88>
8000018c: 00000f17 auipc t5,0x0
80000190: 010f0f13 addi t5,t5,16 # 8000019c <test3>
80000194: 0000a183 lw gp,0(ra)
80000198: 0d40006f j 8000026c <fail>
8000019c <test3>:
8000019c: 00300e13 li t3,3
800001a0: 00000f17 auipc t5,0x0
800001a4: 0ccf0f13 addi t5,t5,204 # 8000026c <fail>
800001a8: 00000117 auipc sp,0x0
800001ac: 01010113 addi sp,sp,16 # 800001b8 <test4>
800001b0: 34111073 csrw mepc,sp
800001b4: 30200073 mret
800001b8 <test4>:
800001b8: 00400e13 li t3,4
800001bc: 00000f17 auipc t5,0x0
800001c0: 0b0f0f13 addi t5,t5,176 # 8000026c <fail>
800001c4: deadc137 lui sp,0xdeadc
800001c8: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc77>
800001cc: 800080b7 lui ra,0x80008
800001d0: 0020a023 sw sp,0(ra) # 80008000 <pass+0x7d88>
800001d4: 00000f17 auipc t5,0x0
800001d8: 010f0f13 addi t5,t5,16 # 800001e4 <test5>
800001dc: 0000a183 lw gp,0(ra)
800001e0: 08c0006f j 8000026c <fail>
800001e4 <test5>:
800001e4: 00500e13 li t3,5
800001e8: deadc137 lui sp,0xdeadc
800001ec: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc77>
800001f0: 800000b7 lui ra,0x80000
800001f4: 0020a023 sw sp,0(ra) # 80000000 <pass+0xfffffd88>
800001f8: 0000a183 lw gp,0(ra)
800001fc: 06311863 bne sp,gp,8000026c <fail>
80000200 <test6>:
80000200: 00600e13 li t3,6
80000204: 800100b7 lui ra,0x80010
80000208: 0000a183 lw gp,0(ra) # 80010000 <pass+0xfd88>
8000020c: 00000f17 auipc t5,0x0
80000210: 06cf0f13 addi t5,t5,108 # 80000278 <pass>
80000214: 0030a023 sw gp,0(ra)
80000218: 0540006f j 8000026c <fail>
8000021c <test7>:
8000021c: 00700e13 li t3,7
80000220: 00000f17 auipc t5,0x0
80000224: 04cf0f13 addi t5,t5,76 # 8000026c <fail>
80000228: deadc137 lui sp,0xdeadc
8000022c: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc77>
80000230: 800300b7 lui ra,0x80030
80000234: ff808093 addi ra,ra,-8 # 8002fff8 <pass+0x2fd80>
80000238: 00222023 sw sp,0(tp) # 0 <_start-0x80000000>
8000023c: 00000f17 auipc t5,0x0
80000240: fa8f0f13 addi t5,t5,-88 # 800001e4 <test5>
80000244: 00022183 lw gp,0(tp) # 0 <_start-0x80000000>
80000248: 0240006f j 8000026c <fail>
8000024c <test8>:
8000024c: 00800e13 li t3,8
80000250: 800400b7 lui ra,0x80040
80000254: ff808093 addi ra,ra,-8 # 8003fff8 <pass+0x3fd80>
80000258: 0000a183 lw gp,0(ra)
8000025c: 00000f17 auipc t5,0x0
80000260: 01cf0f13 addi t5,t5,28 # 80000278 <pass>
80000264: 0030a023 sw gp,0(ra)
80000268: 0040006f j 8000026c <fail>
8000026c <fail>:
8000026c: f0100137 lui sp,0xf0100
80000270: f2410113 addi sp,sp,-220 # f00fff24 <pass+0x700ffcac>
80000274: 01c12023 sw t3,0(sp)
80000278 <pass>:
80000278: f0100137 lui sp,0xf0100
8000027c: f2010113 addi sp,sp,-224 # f00fff20 <pass+0x700ffca8>
80000280: 00012023 sw zero,0(sp)

Binary file not shown.

View File

@ -0,0 +1,44 @@
:0200000480007A
:100000009700000093800001739050306F00C00093
:1000100073101F3473002030130E0000170F000000
:10002000130F0F25B70000803782008037C1ADDE87
:100030001301F1EE23A020002320220083A1000061
:10004000631631228321020063123122B7021207A4
:100050007390023AB7021F19938242307390123A9A
:10006000B7020F00938262507390223AB7221E0F9C
:10007000938202907390323AB70200207390023B51
:100080009302F0FF7390123BB72200207390223B43
:10009000B74200209382F2FF7390323BB7420020B8
:1000A0009382F2FF7390423BB74200209382F2FFAB
:1000B0007390523BB72200209382F2FF7390623B11
:1000C000B76200209382F2FF7390723BB7C20020A8
:1000D0007390823BB7D200207390923B9302F0FF63
:1000E0007390A23B930200007390B23B9302000016
:1000F0007390C23B930200007390D23B93020000C6
:100100007390E23B930200007390F23B3701C10011
:100110001301E1FE23A020002320220083A1000080
:10012000631631149301000083210200631031141F
:10013000130E1000170F0000130F8F13B712920742
:10014000938282807390023AB780008037C1ADDE1F
:100150001301F1EE23A02000170F0000130F0F0171
:1001600083A100006F008010130E2000170F000005
:10017000130F0F10B70212077390023AB780008076
:1001800037C1ADDE1301F1EE23A02000170F0000F0
:10019000130F0F0183A100006F00400D130E3000FC
:1001A000170F0000130FCF0C1701000013010101FE
:1001B0007310113473002030130E4000170F00002D
:1001C000130F0F0B37C1ADDE1301F1EEB7800080C6
:1001D00023A02000170F0000130F0F0183A10000C0
:1001E0006F00C008130E500037C1ADDE1301F1EEF1
:1001F000B700008023A0200083A10000631831060F
:10020000130E6000B700018083A10000170F0000EB
:10021000130FCF0623A030006F004005130E7000AF
:10022000170F0000130FCF0437C1ADDE1301F1EE3D
:10023000B7000380938080FF23202200170F000067
:10024000130F8FFA832102006F004002130E80000B
:10025000B7000480938080FF83A10000170F000087
:10026000130FCF0123A030006F004000370110F0C2
:10027000130141F22320C101370110F0130101F2F3
:040280002320010036
:040000058000000077
:00000001FF

View File

@ -0,0 +1,35 @@
Memory Configuration
Name Origin Length Attributes
onChipRam 0x0000000080000000 0x0000000000020000 w !xr
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
LOAD build/src/crt.o
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a
START GROUP
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libc.a
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libgloss.a
END GROUP
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a
.crt_section 0x0000000080000000 0x284
0x0000000080000000 . = ALIGN (0x4)
*crt.o(.text)
.text 0x0000000080000000 0x284 build/src/crt.o
0x0000000080000000 _start
0x0000000080000010 trap
OUTPUT(build/pmp.elf elf32-littleriscv)
.data 0x0000000080000284 0x0
.data 0x0000000080000284 0x0 build/src/crt.o
.bss 0x0000000080000284 0x0
.bss 0x0000000080000284 0x0 build/src/crt.o
.riscv.attributes
0x0000000000000000 0x1e
.riscv.attributes
0x0000000000000000 0x1e build/src/crt.o

View File

@ -0,0 +1,3 @@
PROJ_NAME=pmp
include ../common/asm.mk

View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2020 Samuel Lindemer <samuel.lindemer@ri.se>
*
* SPDX-License-Identifier: MIT
*/
#define TEST_ID x28
#define TRAP_RA x30
#define PMPCFG0 0x07120000
#define PMPCFG0_ 0x07920808 // locked
#define PMPCFG1 0x191f0304
#define PMPCFG2 0x000f0506
#define PMPCFG3 0x0f1e1900
#define PMPADDR0 0x20000000 // OFF
#define PMPADDR1 0xffffffff // OFF
#define PMPADDR2 0x20002000 // NA4 W
#define PMPADDR3 0x20003fff // OFF RWX
#define PMPADDR4 0x20003fff // OFF X
#define PMPADDR5 0x20003fff // OFF RW
#define PMPADDR6 0x20001fff // NAPOT RWX
#define PMPADDR7 0x20005fff // NAPOT R
#define PMPADDR8 0x2000c000 // TOR W
#define PMPADDR9 0x2000d000 // TOR R
#define PMPADDR10 0xffffffff // TOR RWX
#define PMPADDR11 0x00000000 // OFF
#define PMPADDR12 0x00000000 // OFF
#define PMPADDR13 0x00000000 // NAPOT R
#define PMPADDR14 0x00000000 // NAPOT WX
#define PMPADDR15 0x00000000 // TOR RWX
.global _start
_start:
la x1, trap
csrw mtvec, x1
j test0
.global trap
trap:
csrw mepc, TRAP_RA
mret
// configure PMP, attempt read/write from machine mode
test0:
li TEST_ID, 0
la TRAP_RA, fail
li x1, 0x80000000
li x4, 0x80008000
li x2, 0xdeadbeef
sw x2, 0x0(x1)
sw x2, 0x0(x4)
lw x3, 0x0(x1)
bne x2, x3, fail
lw x3, 0x0(x4)
bne x2, x3, fail
li x5, PMPCFG0
csrw pmpcfg0, x5
li x5, PMPCFG1
csrw pmpcfg1, x5
li x5, PMPCFG2
csrw pmpcfg2, x5
li x5, PMPCFG3
csrw pmpcfg3, x5
li x5, PMPADDR0
csrw pmpaddr0, x5
li x5, PMPADDR1
csrw pmpaddr1, x5
li x5, PMPADDR2
csrw pmpaddr2, x5
li x5, PMPADDR3
csrw pmpaddr3, x5
li x5, PMPADDR4
csrw pmpaddr4, x5
li x5, PMPADDR5
csrw pmpaddr5, x5
li x5, PMPADDR6
csrw pmpaddr6, x5
li x5, PMPADDR7
csrw pmpaddr7, x5
li x5, PMPADDR8
csrw pmpaddr8, x5
li x5, PMPADDR9
csrw pmpaddr9, x5
li x5, PMPADDR10
csrw pmpaddr10, x5
li x5, PMPADDR11
csrw pmpaddr11, x5
li x5, PMPADDR12
csrw pmpaddr12, x5
li x5, PMPADDR13
csrw pmpaddr13, x5
li x5, PMPADDR14
csrw pmpaddr14, x5
li x5, PMPADDR15
csrw pmpaddr15, x5
li x2, 0xc0ffee
sw x2, 0x0(x1)
sw x2, 0x0(x4)
lw x3, 0x0(x1)
bne x2, x3, fail
li x3, 0x0
lw x3, 0x0(x4)
bne x2, x3, fail
// lock region 2, attempt read/write from machine mode
test1:
li TEST_ID, 1
la TRAP_RA, fail
li x5, PMPCFG0_
csrw pmpcfg0, x5 // lock region 2
li x1, 0x80008000
li x2, 0xdeadbeef
sw x2, 0x0(x1) // should be OK (write 0x80008000)
la TRAP_RA, test2
lw x3, 0x0(x1) // should fault (read 0x80008000)
j fail
// "unlock" region 2, attempt read/write from machine mode
test2:
li TEST_ID, 2
la TRAP_RA, fail
li x5, PMPCFG0
csrw pmpcfg0, x5 // "unlock" region 2
li x1, 0x80008000
li x2, 0xdeadbeef
sw x2, 0x0(x1) // should still be OK (write 0x80008000)
la TRAP_RA, test3
lw x3, 0x0(x1) // should still fault (read 0x80008000)
j fail
// jump into user mode
test3:
li TEST_ID, 3
la TRAP_RA, fail
la x2, test4
csrw mepc, x2
mret
// attempt to read/write region 2 from user mode
test4:
li TEST_ID, 4
la TRAP_RA, fail
li x2, 0xdeadbeef
li x1, 0x80008000
sw x2, 0x0(x1) // should be OK (write 0x80008000)
la TRAP_RA, test5
lw x3, 0x0(x1) // should fault (read 0x80008000)
j fail
// attempt to read/write other regions from user mode
test5:
li TEST_ID, 5
li x2, 0xdeadbeef
li x1, 0x80000000
sw x2, 0x0(x1)
lw x3, 0x0(x1)
bne x2, x3, fail // should be OK (read/write 0x80000000)
test6:
li TEST_ID, 6
li x1, 0x80010000
lw x3, 0x0(x1) // should be OK (read 0x80010000)
la TRAP_RA, pass
sw x3, 0x0(x1) // should fault (write 0x80010000)
j fail
test7:
li TEST_ID, 7
la TRAP_RA, fail
li x2, 0xdeadbeef
li x1, 0x8002fff8
sw x2, 0x0(x4) // should be OK (write 0x8002fff8)
la TRAP_RA, test5
lw x3, 0x0(x4) // should fault (read 0x8002fff8)
j fail
test8:
li TEST_ID, 8
li x1, 0x8003fff8
lw x3, 0x0(x1) // should be OK (read 0x8003fff8)
la TRAP_RA, pass
sw x3, 0x0(x1) // should fault (write 0x8003fff8)
j fail
fail:
li x2, 0xf00fff24
sw TEST_ID, 0(x2)
pass:
li x2, 0xf00fff20
sw x0, 0(x2)

View File

@ -0,0 +1,16 @@
OUTPUT_ARCH( "riscv" )
MEMORY {
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K
}
SECTIONS
{
.crt_section :
{
. = ALIGN(4);
*crt.o(.text)
} > onChipRam
}

View File

@ -3870,6 +3870,10 @@ int main(int argc, char **argv, char **env) {
redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3););
#endif
#ifdef PMP
redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x80000000u)->run(10e3););
#endif
#ifdef AMO
redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3););
#endif

View File

@ -15,6 +15,7 @@ CSR_SKIP_TEST?=no
EBREAK?=no
FENCEI?=no
MMU?=yes
PMP?=no
SEED?=no
LRSC?=no
AMO?=no
@ -217,6 +218,10 @@ ifeq ($(MMU),yes)
ADDCFLAGS += -CFLAGS -DMMU
endif
ifeq ($(PMP),yes)
ADDCFLAGS += -CFLAGS -DPMP
endif
ifeq ($(MUL),yes)
ADDCFLAGS += -CFLAGS -DMUL
endif

View File

@ -46,8 +46,10 @@ abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvCo
class VexRiscvUniverse extends ConfigUniverse
object VexRiscvUniverse{
val CACHE_ALL = new VexRiscvUniverse
val CATCH_ALL = new VexRiscvUniverse
val MMU = new VexRiscvUniverse
val PMP = new VexRiscvUniverse
val FORCE_MULDIV = new VexRiscvUniverse
val SUPERVISOR = new VexRiscvUniverse
val NO_WRITEBACK = new VexRiscvUniverse
@ -321,9 +323,10 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL)
val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null
if(r.nextDouble() < 0.5){
if(r.nextDouble() < 0.5 && !cacheAll){
val latency = r.nextInt(5) + 1
val compressed = r.nextDouble() < rvcRate
val injectorStage = r.nextBoolean() || latency == 1
@ -402,13 +405,14 @@ class DBusDimension extends VexRiscvDimension("DBus") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL)
val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null
val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY)
val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK)
if(r.nextDouble() < 0.4 || noMemory){
if((r.nextDouble() < 0.4 || noMemory) && !cacheAll){
val withLrSc = catchAll
val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK)
new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) {
@ -468,12 +472,12 @@ class DBusDimension extends VexRiscvDimension("DBus") {
}
class MmuDimension extends VexRiscvDimension("DBus") {
class MmuPmpDimension extends VexRiscvDimension("DBus") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
if(universes.contains(VexRiscvUniverse.MMU)) {
new VexRiscvPosition("WithMmu") {
override def testParam = "MMU=yes"
override def testParam = "MMU=yes PMP=no"
override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new MmuPlugin(
@ -481,9 +485,20 @@ class MmuDimension extends VexRiscvDimension("DBus") {
)
}
}
} else if (universes.contains(VexRiscvUniverse.PMP)) {
new VexRiscvPosition("WithPmp") {
override def testParam = "MMU=no PMP=yes"
override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new PmpPlugin(
regions = 16,
ioRange = _ (31 downto 28) === 0xF
)
}
}
} else {
new VexRiscvPosition("NoMmu") {
override def testParam = "MMU=no"
new VexRiscvPosition("NoMemProtect") {
override def testParam = "MMU=no PMP=no"
override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new StaticMemoryTranslatorPlugin(
@ -502,6 +517,7 @@ trait CatchAllPosition
class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val pmp = universes.contains(VexRiscvUniverse.PMP)
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR)
if(supervisor){
@ -509,10 +525,15 @@ class CsrDimension(freertos : String, zephyr : String, linux : String) extends V
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l))
override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes"
}
} else if(pmp){
new VexRiscvPosition("Secure") with CatchAllPosition{
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.secure(0x80000020l))
override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr"
}
} else if(catchAll){
new VexRiscvPosition("MachineOs") with CatchAllPosition{
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l))
override def testParam = s"CSR=yes FREERTOS=$freertos ZEPHYR=$zephyr"
override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr"
}
} else if(r.nextDouble() < 0.3){
new VexRiscvPosition("AllNoException") with CatchAllPosition{
@ -640,6 +661,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite {
val rvcRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_RVC_RATE", "0.5").toDouble
val linuxRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble
val machineOsRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble
val secureRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_SECURE_RATE", "0.5").toDouble
val linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")
val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")
val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")
@ -661,7 +683,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite {
new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken
new DecoderDimension,
new DebugDimension,
new MmuDimension
new MmuPmpDimension
)
var clockCounter = 0l
@ -746,6 +768,13 @@ class TestIndividualFeatures extends MultithreadedFunSuite {
if(demwRate < rand.nextDouble()){
universe += VexRiscvUniverse.NO_WRITEBACK
}
} else if (secureRate > rand.nextDouble()) {
universe += VexRiscvUniverse.CACHE_ALL
universe += VexRiscvUniverse.CATCH_ALL
universe += VexRiscvUniverse.PMP
if(demwRate < rand.nextDouble()){
universe += VexRiscvUniverse.NO_WRITEBACK
}
} else {
if(machineOsRate > rand.nextDouble()) {
universe += VexRiscvUniverse.CATCH_ALL
@ -776,4 +805,4 @@ class TestIndividualFeatures extends MultithreadedFunSuite {
val clockPerSecond = (clockCounter/time*1e-3).toLong
println(s"Duration=${(time/60).toInt}mn clocks=${(clockCounter*1e-6).toLong}M clockPerSecond=${clockPerSecond}K")
}
}
}