Running Linux on Spike

This article is about how to get Linux running on the RISC-V simulator. I tried multiple ways of getting this going and it took quite some of my time, so I hope this article will help others get started more quickly.

Prerequisites

Before you get started, I will run through a couple of requirements here. I have tested these commands on the 64-bit version of Ubuntu 18.04.3 LTS. Also, after downloading the source code and building all the necessary files, this project takes up approximately 10 GB of space on disk. Another prerequisite is that you are relatively familiar with using a Linux terminal.

The software project that I found works best to boot Linux on Spike was to use the SiFive Freedom-U-SDK. Our first step is to download the build dependencies for our project. This is all described in the README.md file but I will include it here for completeness.

apt install build-essential git autoconf libtool gnulib texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev gawk zlib1g-dev libssl-dev device-tree-compiler python

Make sure that you don't have a previous version of RISC-V tools in your path and check that your RISCV environment variable is unset by checking that the output of the following command is blank:

echo $RISCV

The run-time numbers that I give below are an indication and are based on my machine with an Intel i7-4770 CPU and 32 GB of DRAM.

Building

Next, we will download the source files from their github repository. Make sure you are in a folder where you want your source code to live. The following command will make a directory called freedom-u-sdk inside your current directory and put the source files in there:

git clone https://github.com/sifive/freedom-u-sdk.git

I've found that whether I am able to build this repository or not depends on which commit I am on. So to make sure you are on the same commit number of the repository as I am run the following commands:

cd freedom-u-sdk/
git checkout ea9879339b937d1d5f90073a3ae37d8c78b141f7

The main purpose of this repository is to be a collection of other repositories and which versions work well together. For example, you can see a linux folder for the operating system and a riscv-isa-sim folder for the Spike simulator. After cloning, these folders are still empty, because they are references to other repositories. So let us initialize all the submodules (which took me about 15 minutes):

git submodule update --recursive --init

Now our sub-folders should be populated and our folder is also significantly bigger in size (~2.3 GB). According to the read-me file you might need to run this command a couple of times for it to succeed.

Unlike the instructions in the read-me file, we need to make a couple of changes before we can actually build our project. First, we must check out another branch of buildroot. To do this execute the following commands:

cd buildroot
git checkout sifive
git checkout c4ddfe7a5fd964274c99033bd87df3dc7534d196
cd ..

You may skip the second git checkout command if you like, but I have included it to make sure you are on the exact commit that I used to verify this tutorial. After this initial modification we can run through the first step of building by invoking make, which takes about an hour for me and increases the size of our folder to 9 GB:

make

Afterwards, we can make our second modification, which we can do by editing conf/linux_defconfig We will change line 56 to:

CONFIG_HVC_RISCV_SBI=y

You may use your favorite text editor for this. One example is to use the standard GUI text editor in Ubuntu:

gedit conf/linux_defconfig

For clarity here is the diff of conf/linux_defconfig after the edit:

diff --git a/conf/linux_defconfig b/conf/linux_defconfig
index cd87340..db83d12 100644
--- a/conf/linux_defconfig
+++ b/conf/linux_defconfig
@@ -53,7 +53,7 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_SIFIVE=y
 CONFIG_SERIAL_SIFIVE_CONSOLE=y
-# CONFIG_HVC_RISCV_SBI is not set
+CONFIG_HVC_RISCV_SBI=y
 CONFIG_VIRTIO_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y

Booting Linux

Finally, to complete our build as well as run our Spike simulator, we can run the final build command, which took me about 9 minutes in the first instance:

make sim

This is also the command that you need to run on sub-sequent runs. make sim should run a lot quicker once the building is done. Upon booting of Linux, you should be greeted with the SiFive logo:

         5555555555555555555555555
        5555                   5555
       5555                     5555
      5555                       5555
     5555       5555555555555555555555
    5555       555555555555555555555555
   5555                             5555
  5555                               5555
 5555                                 5555
5555555555555555555555555555          55555
 55555           555555555           55555
   55555           55555           55555
     55555           5           55555
       55555                   55555
         55555               55555
           55555           55555
             55555       55555
               55555   55555
                 555555555
                   55555
                     5

To log in use the following login credentials:

Username: root
Password: sifive

This gives you a complete Buildroot Linux to play with. To shut down this version of linux, you can use the halt command.

Modifying Root Filesystem

In this section, we will talk about how to put your own programs onto the Spike simulator to run. The way that I do this is by making a change to the target file system. Making a change in a file that causes a re-build and then running Linux again.

To make a change in our root file system, you should add any file you want into work/buildroot_initramfs_sysroot/ This folder contains the root file system of the Linux that you're running on Spike.

Once you've added your files, make a small change to conf/linux_defconfig For example, you can add a new comment character (#) to the end of the file. This simply forces the make command to look at your updated file system.

Once that is done you can re-run your run command make sim After logging in you should see the files you put into the root file system.

To make this job a bit quicker, I made a small bash script to do the compile software and copy the executible files to the root file system directory and the rest of the update process. This is what my script looks like:

#!/bin/sh -x
SIFIVE_DIR=/path/to/your/freedom-u-sdk
SOURCE_DIR=/path/to/your/sources
cd $SOURCE_DIR
make
sudo cp $SOURCE_DIR/*.exe $SIFIVE_DIR/work/buildroot_initramfs_sysroot/usr/
echo "#" >> $SIFIVE_DIR/conf/linux_defconfig
cd $SIFIVE_DIR
make sim

Make sure to change your directory paths. The reason why I use sudo for the copy command is because I want the owner of the files to be root once I boot up Linux on Spike, since root is the only user that exists by default on our build.

Adding Syscalls to the Kernel

Let's say you want to add a syscall called mycall. I've adapted the instructions in this section from Amit Choudhary. Make the following modifications in the linux directory:

Create a file linux/drivers/mycall/mycall.c with the following content:

#include<linux/linkage.h>

asmlinkage long sys_mycall(int i) {
 return i+10;
}

Now to test the new syscall, use the following C code, which should output 25:

#include<asm-generic/unistd.h>
#include<stdio.h>

long mycall(int i) {
 return syscall(__NR_mycall, i);
}

int main(void) {
 printf("%d\n", mycall(15));
}

To compile the test code run riscv64-unknown-linux-gnu-gcc test.c and copy the file, a.out into the file system using the instructions from the previous section.

I hope this tutorial has been useful for you and that it made getting Linux running on Spike less painful than it was for me. Happy hacking!