resources: update riscv-fs resource for gem5-develop

This change also removes the device.dts file as bbl
no longer needs to be compiled with a device tree rather
it can be created through gem5 config scripts.

Change-Id: Ib52dc8709c436efc3afd4951a413d4477555b6ab
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5-resources/+/46019
Reviewed-by: Hoa Nguyen <hoanguyen@ucdavis.edu>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: Jason Lowe-Power <power.jg@gmail.com>
diff --git a/src/riscv-fs/README.md b/src/riscv-fs/README.md
index 08b386e..cdca282 100644
--- a/src/riscv-fs/README.md
+++ b/src/riscv-fs/README.md
@@ -17,7 +17,7 @@
 
 The used disk image is based on [busybox](https://busybox.net/) and [UCanLinux](https://github.com/UCanLinux/). It is built using the instructions, mostly from [here](https://github.com/UCanLinux/riscv64-sample).
 
-All components are cross compiled on an x86 host using a riscv tool chain.
+**Note:** All components are cross compiled on an x86 host using a riscv tool chain. We used `88b004d4c2a7d4e4f08b17ee32d2` commit of the riscv tool chain source while building the source (riscv gcc version 10.2.0).
 
 We assume the following directory structure while following the instructions in this README file:
 
@@ -27,8 +27,6 @@
   |
   |___ riscv-disk                              # built disk image will go here
   |
-  |___ device.dts                              # device tree file to use with bbl
-  |
   |___ riscv-gnu-toolchain                     # riscv tool chain for cross compilation
   |
   |___ riscv64-sample                          # UCanLinux source
@@ -57,6 +55,7 @@
 # clone riscv gnu toolchain source
 git clone https://github.com/riscv/riscv-gnu-toolchain
 cd riscv-gnu-toolchain
+git checkout 88b004d4c2a7d4e4f08b17ee32d2
 
 # change the prefix to your directory
 # of choice for installation of the
@@ -86,7 +85,7 @@
 git clone https://github.com/UCanLinux/riscv64-sample
 ```
 
-This source contains already built bootloader and disk images as well. Though the given disk image might be usable with gem5, the `bbl` (bootloader image) will not work with gem5 and we need to compile `bbl` with an input device tree (`.dts`) file separately. The following sections provide instructions to build both `bbl` and disk images.
+The following sections provide instructions to build both `bbl` and disk images.
 
 ## Linux Kernel
 
@@ -130,10 +129,9 @@
 
 apt-get install device-tree-compiler
 
-# copy the device tree file from riscv-fs
-cp ../../../device.dts .
+# configure bbl build
+../configure --host=riscv64-unknown-linux-gnu --with-payload=../../linux/vmlinux --prefix=/opt/riscv/
 
-../configure --host=riscv64-unknown-linux-gnu --with-payload=../../linux/vmlinux --prefix=/opt/riscv/ --with-dts=device.dts
 make -j$(nproc)
 
 chmod 755 bbl
@@ -155,7 +153,7 @@
 cd busybox
 git checkout 1_30_stable  # checkout the latest stable branch
 make menuconfig
-cp ../sample/busybox.config .config  # optional
+cp ../busybox.config .config  # optional
 make menuconfig
 make CROSS_COMPILE=riscv64-unknown-linux-gnu- all -j$(nproc)
 make CROSS_COMPILE=riscv64-unknown-linux-gnu- install
@@ -167,7 +165,7 @@
 
 ```sh
 # going back to riscv64-sample directory
-cd ../..
+cd ../
 
 mkdir RootFS
 cd RootFS
@@ -191,10 +189,10 @@
 
 # build m5 util for riscv and move
 # it to the root file system as well
-cd ../../../
+cd ../../../../
 cd gem5/util/m5
-scons -C util/m5 build/riscv/out/m5
-cp build/riscv/out/m5 ../../../RootFS/sbin/
+scons build/riscv/out/m5
+cp build/riscv/out/m5 ../../../riscv64-sample/RootFS/sbin/
 ```
 
 ## Disk Image
@@ -214,12 +212,10 @@
 sudo mkdir /mnt/rootfs
 sudo mount riscv_disk /mnt/rootfs
 
-sudo cp -a RootFS/* /mnt/rootfs
+sudo cp -a riscv64-sample/RootFS/* /mnt/rootfs
 
 sudo chown -R -h root:root /mnt/rootfs/
 df /mnt/rootfs
-# make sure you are in riscv64-sample dir
-cd ../riscv64-sample
 sudo umount /mnt/rootfs
 ```
 
@@ -254,7 +250,7 @@
 An example use of this script is the following:
 
 ```sh
-[gem5 binary] -re configs/run_exit.py [path to bbl] [path to the disk image] atomic 4
+[gem5 binary] -re configs/run_riscv.py [path to bbl] [path to the disk image] atomic 1
 ```
 
 To interact with the simulated system's console:
diff --git a/src/riscv-fs/configs-riscv-fs/run_riscv.py b/src/riscv-fs/configs-riscv-fs/run_riscv.py
index 1ca8665..3e3b747 100755
--- a/src/riscv-fs/configs-riscv-fs/run_riscv.py
+++ b/src/riscv-fs/configs-riscv-fs/run_riscv.py
@@ -26,8 +26,8 @@
 
 """
 This script is supposed to run full system simulation for RISCV targets.
-It has been tested with classic memory system and Atomic
-and TimingSimpleCPU so far.
+It has been tested with classic memory system and Atomic,
+TimingSimpleCPU, and MinorCPU so far.
 """
 
 import time
diff --git a/src/riscv-fs/configs-riscv-fs/system/system.py b/src/riscv-fs/configs-riscv-fs/system/system.py
index 0150972..94dfd6c 100755
--- a/src/riscv-fs/configs-riscv-fs/system/system.py
+++ b/src/riscv-fs/configs-riscv-fs/system/system.py
@@ -23,10 +23,12 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
 
 import m5
 from m5.objects import *
 from m5.util import convert
+from os import path
 
 '''
 This class creates a bare bones RISCV full system.
@@ -37,6 +39,43 @@
 d3c2-44ea-85fb-acc1df282e21_FU540-C000-v1p3.pdf
 '''
 
+# Dtb generation code from configs/example/riscv/fs_linux.py
+def generateMemNode(state, mem_range):
+    node = FdtNode("memory@%x" % int(mem_range.start))
+    node.append(FdtPropertyStrings("device_type", ["memory"]))
+    node.append(FdtPropertyWords("reg",
+        state.addrCells(mem_range.start) +
+        state.sizeCells(mem_range.size()) ))
+    return node
+
+def generateDtb(system):
+    """
+    Autogenerate DTB. Arguments are the folder where the DTB
+    will be stored, and the name of the DTB file.
+    """
+    state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1)
+    root = FdtNode('/')
+    root.append(state.addrCellsProperty())
+    root.append(state.sizeCellsProperty())
+    root.appendCompatible(["riscv-virtio"])
+
+    for mem_range in system.mem_ranges:
+        root.append(generateMemNode(state, mem_range))
+
+    sections = [*system.cpu, system.platform]
+
+    for section in sections:
+        for node in section.generateDeviceTree(state):
+            if node.get_name() == root.get_name():
+                root.merge(node)
+            else:
+                root.append(node)
+
+    fdt = Fdt()
+    fdt.add_rootnode(root)
+    fdt.writeDtsFile(path.join(m5.options.outdir, 'device.dts'))
+    fdt.writeDtbFile(path.join(m5.options.outdir, 'device.dtb'))
+
 class RiscvSystem(System):
 
     def __init__(self, bbl, disk, cpu_type, num_cpus):
@@ -55,41 +94,24 @@
         # This connects to main memory
         self.membus = SystemXBar(width = 64) # 64-byte width
 
+        # Add a bad addr responder
+        self.membus.badaddr_responder = BadAddr()
+        self.membus.default = self.membus.badaddr_responder.pio
+
         # Set up the system port for functional access from the simulator
         self.system_port = self.membus.cpu_side_ports
 
         # Create the CPUs for our system.
         self.createCPU(cpu_type, num_cpus)
 
-        # using RISCV bare metal as the base full system workload
-        self.workload = RiscvBareMetal()
-
-        # this is user passed berkeley boot loader binary
-        # currently the Linux kernel payload is compiled into this
-        # as well
-        self.workload.bootloader = bbl
-
         # HiFive platform
         # This is based on a HiFive RISCV board and has
         # only a limited number of devices so far i.e.
         # PLIC, CLINT, UART, VirtIOMMIO
         self.platform = HiFive()
 
-        # Next, create and intialize devices
-        # currently supported for RISCV
-
-        # add a disk image
-        self.attachDisk(disk)
-
-        # set up core and platform
-        # level interrupt controllers
-        self.setupIntrCtrl()
-
-        # set up PMA checker
-        self.pmaChecker()
-
-        # attach off and on chip IO
-        self.attachIO(self.membus)
+        # create and intialize devices currently supported for RISCV
+        self.initDevices(self.membus, disk)
 
         # Create the cache heirarchy for the system.
         self.createCacheHierarchy()
@@ -99,6 +121,28 @@
 
         self.setupInterrupts()
 
+        # using RiscvLinux as the base full system workload
+        self.workload = RiscvLinux()
+
+        # this is user passed berkeley boot loader binary
+        # currently the Linux kernel payload is compiled into this
+        # as well
+        self.workload.object_file = bbl
+
+        # Generate DTB (from configs/example/riscv/fs_linux.py)
+        generateDtb(self)
+        self.workload.dtb_filename = path.join(m5.options.outdir, 'device.dtb')
+        # Default DTB address if bbl is bulit with --with-dts option
+        self.workload.dtb_addr = 0x87e00000
+
+        # Linux boot command flags
+        kernel_cmd = [
+            "console=ttyS0",
+            "root=/dev/vda",
+            "ro"
+        ]
+        self.workload.command_line = " ".join(kernel_cmd)
+
     def createCPU(self, cpu_type, num_cpus):
         if cpu_type == "atomic":
             self.cpu = [AtomicSimpleCPU(cpu_id = i)
@@ -108,6 +152,10 @@
             self.cpu = [TimingSimpleCPU(cpu_id = i)
                         for i in range(num_cpus)]
             self.mem_mode = 'timing'
+        elif cpu_type == "minor":
+            self.cpu = [MinorCPU(cpu_id = i)
+                        for i in range(num_cpus)]
+            self.mem_mode = 'timing'
         else:
             m5.fatal("No CPU type {}".format(cpu_type))
 
@@ -170,20 +218,11 @@
                     port = self.membus.mem_side_ports)
         ]
 
-    def attachIO(self, membus):
+    def initDevices(self, membus, disk):
+
         self.iobus = IOXBar()
+        self.intrctrl = IntrControl()
 
-        self.bridge = Bridge(delay='50ns')
-        self.bridge.master = self.iobus.slave
-        self.bridge.slave = self.membus.master
-        self.bridge.ranges = self.platform._off_chip_ranges()
-
-        # Connecting on chip and off chip IO to the mem
-        # and IO bus
-        self.platform.attachOnChipIO(self.membus)
-        self.platform.attachOffChipIO(self.iobus)
-
-    def setupIntrCtrl(self):
         # Set the frequency of RTC (real time clock) used by
         # CLINT (core level interrupt controller).
         # This frequency is 1MHz in SiFive's U54MC.
@@ -193,12 +232,17 @@
         # RTC sends the clock signal to CLINT via an interrupt pin.
         self.platform.clint.int_pin = self.platform.rtc.int_pin
 
-        # Attach the PLIC (platform level interrupt controller)
-        # to the platform. This initializes the PLIC with
-        # interrupt sources coming from off chip devices
-        self.platform.attachPlic()
+        # VirtIOMMIO
+        image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False)
+        image.child.image_file = disk
+        # using reserved memory space
+        self.platform.disk = MmioVirtIO(
+            vio=VirtIOBlock(image=image),
+            interrupt_id=0x8,
+            pio_size = 4096,
+            pio_addr=0x10008000
+        )
 
-    def pmaChecker(self):
         # From riscv/fs_linux.py
         uncacheable_range = [
             *self.platform._on_chip_ranges(),
@@ -211,16 +255,20 @@
         # or MMU-level (system.cpu[0].mmu.pma_checker). It will be resolved
         # by RiscvTLB's Parent.any proxy
 
-        self.pma_checker =  PMAChecker(uncacheable=uncacheable_range)
+        for cpu in self.cpu:
+            cpu.mmu.pma_checker =  PMAChecker(uncacheable=uncacheable_range)
 
-    def attachDisk(self, disk):
-        # VirtIOMMIO
-        image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False)
-        image.child.image_file = disk
-        # using reserved memory space
-        self.platform.disk = MmioVirtIO(
-            vio=VirtIOBlock(image=image),
-            interrupt_id=0x8,
-            pio_size = 4096,
-            pio_addr=0x10008000
-        )
+        self.bridge = Bridge(delay='50ns')
+        self.bridge.mem_side_port = self.iobus.cpu_side_ports
+        self.bridge.cpu_side_port = self.membus.mem_side_ports
+        self.bridge.ranges = self.platform._off_chip_ranges()
+
+        # Connecting on chip and off chip IO to the mem
+        # and IO bus
+        self.platform.attachOnChipIO(self.membus)
+        self.platform.attachOffChipIO(self.iobus)
+
+        # Attach the PLIC (platform level interrupt controller)
+        # to the platform. This initializes the PLIC with
+        # interrupt sources coming from off chip devices
+        self.platform.attachPlic()
diff --git a/src/riscv-fs/device.dts b/src/riscv-fs/device.dts
deleted file mode 100644
index 7181c6c..0000000
--- a/src/riscv-fs/device.dts
+++ /dev/null
@@ -1,80 +0,0 @@
-/dts-v1/;
-
-/ {
-	#address-cells = <0x2>;
-	#size-cells = <0x2>;
-	compatible = "riscv-virtio";
-	model = "riscv-virtio,qemu";
-
-	chosen {
-		bootargs = "root=/dev/vda ro console=ttyS0";
-		stdout-path = "/soc/uart@10000000";
-	};
-
-	memory@80000000 {
-		device_type = "memory";
-		reg = <0x0 0x80000000 0x0 0x8000000>;
-	};
-
-	cpus {
-		#address-cells = <0x1>;
-		#size-cells = <0x0>;
-		timebase-frequency = <0x989680>;
-
-		cpu@0 {
-			phandle = <0x1>;
-			device_type = "cpu";
-			reg = <0x0>;
-			status = "okay";
-			compatible = "riscv";
-			riscv,isa = "rv64imafdcsu";
-			mmu-type = "riscv,sv48";
-
-			interrupt-controller {
-				#interrupt-cells = <0x1>;
-				interrupt-controller;
-				compatible = "riscv,cpu-intc";
-				phandle = <0x2>;
-			};
-		};
-	};
-
-	soc {
-		#address-cells = <0x2>;
-		#size-cells = <0x2>;
-		compatible = "simple-bus";
-		ranges;
-
-		uart@10000000 {
-			interrupts = <0xa>;
-			interrupt-parent = <0x3>;
-			clock-frequency = <0x384000>;
-			reg = <0x0 0x10000000 0x0 0x008>;
-			compatible = "ns8250";
-		};
-
-		plic@c000000 {
-			phandle = <0x3>;
-			riscv,ndev = <0xa>;
-			reg = <0x0 0xc000000 0x0 0x210000>;
-			interrupts-extended = <0x2 0xb 0x2 0x9>;
-			interrupt-controller;
-			compatible = "riscv,plic0";
-			#interrupt-cells = <0x1>;
-			#address-cells = <0x0>;
-		};
-
-		virtio_mmio@10008000 {
-			interrupts = <0x8>;
-			interrupt-parent = <0x3>;
-			reg = <0x0 0x10008000 0x0 0x1000>;
-			compatible = "virtio,mmio";
-		};
-
-		clint@2000000 {
-			interrupts-extended = <0x2 0x3 0x2 0x7>;
-			reg = <0x0 0x2000000 0x0 0x10000>;
-			compatible = "riscv,clint0";
-		};
-	};
-};