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:
- To file
linux/drivers/Makefile
addobj-y += mycall/
- Create folder
linux/drivers/mycall
- Create file
linux/drivers/mycall/Makefile
with contentobj-y := mycall.o
- In file
linux/include/linux/syscall.h
insertasmlinkage long sys_mycall(int i);
at line 943 - In file
linux/uapi/asm-generic/unistd.h
insert#define __NR_mycall 292
and__SYSCALL(__NR_mycall, sys_mycall)
at line 735 - In the same file change the value of
__NR_syscalls
to293
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!