From 0d76e96b886a46ca0c0382e82b9538df4ea82c0c Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 7 Aug 2017 18:30:38 -0700 Subject: [PATCH] tilelink: PMP controlled BusBlocker prevents bus accesses --- .../scala/devices/tilelink/BusBlocker.scala | 108 ++++++++++++++++++ .../scala/devices/tilelink/BusBypass.scala | 18 +-- 2 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 src/main/scala/devices/tilelink/BusBlocker.scala diff --git a/src/main/scala/devices/tilelink/BusBlocker.scala b/src/main/scala/devices/tilelink/BusBlocker.scala new file mode 100644 index 00000000..9403fa00 --- /dev/null +++ b/src/main/scala/devices/tilelink/BusBlocker.scala @@ -0,0 +1,108 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.devices.tilelink + +import Chisel._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ + +case class BusBlockerParams( + controlAddress: BigInt, + controlBeatBytes: Int, + deviceBeatBytes: Int, + pmpRegisters: Int) +{ + val page = 4096 + val size = (((pmpRegisters * 8) + page - 1) / page) * page + + require (pmpRegisters > 0) + require (controlAddress > 0) + require (controlAddress % size == 0) + require (controlBeatBytes > 0 && isPow2(controlBeatBytes)) + require (deviceBeatBytes > 0 && isPow2(deviceBeatBytes)) +} + +case class DevicePMPParams(addressBits: Int) +class DevicePMP(params: DevicePMPParams) extends GenericParameterizedBundle(params) +{ + require (params.addressBits > 12) + + val l = UInt(width = 1) // locked + val a = UInt(width = 1) // LSB of A (0=disabled, 1=TOR) + val r = UInt(width = 1) + val w = UInt(width = 1) + + val addr_hi = UInt(width = params.addressBits-12) + def address = Cat(addr_hi, UInt(0, width=12)) + + def fields(locked: Bool): Seq[RegField] = { + def field(bits: Int, reg: UInt) = + RegField(bits, RegReadFn(reg), RegWriteFn((wen, data) => { + when (wen && !locked) { reg := data } + Bool(true) + })) + Seq( + RegField(10), + field(params.addressBits-12, addr_hi), + RegField(56 - (params.addressBits-2)), + field(1, r), + field(1, w), + RegField(1), // x + field(1, a), + RegField(3), // a high + 2 reserved + field(1, l)) + } +} + +object DevicePMP +{ + def apply(addressBits: Int) = { + val out = Wire(new DevicePMP(DevicePMPParams(addressBits))) + out.l := UInt(0) + out.a := UInt(1) // TOR + out.r := UInt(0) + out.w := UInt(0) + out.addr_hi := ~UInt(0, width=addressBits-12) + out + } +} + +class BusBlocker(params: BusBlockerParams)(implicit p: Parameters) extends TLBusBypassBase(params.deviceBeatBytes) +{ + val device = new SimpleDevice("bus-blocker", Seq("sifive,bus-blocker0")) + + val controlNode = TLRegisterNode( + address = Seq(AddressSet(params.controlAddress, params.size-1)), + device = device, + beatBytes = params.controlBeatBytes) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val ctl = controlNode.bundleIn + val in = nodeIn.bundleIn + val out = nodeOut.bundleOut + } + + // We need to be able to represent +1 larger than the largest populated address + val addressBits = log2Ceil(nodeOut.edgesOut(0).manager.maxAddress+1+1) + val pmps = RegInit(Vec.fill(params.pmpRegisters) { DevicePMP(addressBits) }) + val locks = (pmps.map(_.l) zip (UInt(0) +: pmps.map(_.l))) map { case (x, n) => x | n } + controlNode.regmap(0 -> (pmps zip locks).map { case (p, l) => p.fields(l(0)) }.toList.flatten) + + val in = io.in(0) + val edge = nodeIn.edgesIn(0) + + // Determine if a request is allowed + val needW = in.a.bits.opcode =/= TLMessages.Get + val needR = in.a.bits.opcode =/= TLMessages.PutFullData && in.a.bits.opcode =/= TLMessages.PutPartialData + val lte = Bool(false) +: pmps.map(in.a.bits.address < _.address) + val sel = (pmps.map(_.a) zip (lte.init zip lte.tail)) map { case (a, (l, r)) => a(0) && !l && r } + val ok = pmps.map(p => (p.r(0) || !needR) && (p.w(0) || !needW)) + val allow = PriorityMux(sel :+ Bool(true), ok :+ Bool(true)) // no match => allow + + bar.module.io.bypass := !allow + } +} diff --git a/src/main/scala/devices/tilelink/BusBypass.scala b/src/main/scala/devices/tilelink/BusBypass.scala index 4bba4bd5..784d9c86 100644 --- a/src/main/scala/devices/tilelink/BusBypass.scala +++ b/src/main/scala/devices/tilelink/BusBypass.scala @@ -10,19 +10,23 @@ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util._ import scala.math.min -class TLBusBypass(beatBytes: Int)(implicit p: Parameters) extends LazyModule +abstract class TLBusBypassBase(beatBytes: Int)(implicit p: Parameters) extends LazyModule { - private val nodeIn = TLInputNode() - private val nodeOut = TLOutputNode() + protected val nodeIn = TLInputNode() + protected val nodeOut = TLOutputNode() val node = NodeHandle(nodeIn, nodeOut) - private val bar = LazyModule(new TLBusBypassBar) - private val everything = Seq(AddressSet(0, BigInt("ffffffffffffffffffffffffffffffff", 16))) // 128-bit - private val error = LazyModule(new TLError(ErrorParams(everything), beatBytes)) + protected val bar = LazyModule(new TLBusBypassBar) + protected val everything = Seq(AddressSet(0, BigInt("ffffffffffffffffffffffffffffffff", 16))) // 128-bit + protected val error = LazyModule(new TLError(ErrorParams(everything), beatBytes)) + bar.node := nodeIn error.node := bar.node nodeOut := bar.node +} +class TLBusBypass(beatBytes: Int)(implicit p: Parameters) extends TLBusBypassBase(beatBytes) +{ lazy val module = new LazyModuleImp(this) { val io = new Bundle { val in = nodeIn.bundleIn @@ -33,7 +37,7 @@ class TLBusBypass(beatBytes: Int)(implicit p: Parameters) extends LazyModule } } -private class TLBusBypassBar(implicit p: Parameters) extends LazyModule +class TLBusBypassBar(implicit p: Parameters) extends LazyModule { // The client only sees the second slave port val node = TLNexusNode(