RISCV is going to be a serious player in the ecosystem maybe 5 years down the line. It makes sense to stay on its forefront, doesn't it?

Most of the infrastructure needed for building Linux on a RISCV64 machine is upstream. You even have full fledged Linux distributions available you can just download and fireup on QEMU. But I set about to cook the whole thing myself.

Buildroot

You can easily build a full Linux distribution using Buildroot. It is a Makefile and Kconfig based build system for building the kernel and an associated userspace for embedded systems. But nothing is stopping you from building a full OS for your normal desktop/laptop too!

I used the latest stable release, 2018.11.2 with some modifications to get it to work. Building an image is as simple as below:

make menuconfig
make

It could not get any simpler. You also have the option of xconfig instead of menuconfig, just like the Linux Kernel configuration system. Depending on your machine and configuration options, it can take quite a lot of time to finish the build. It will automagically download all the necessary sources, cross compiles the toolchain, builds the kernel, libraries and usespace applications and finally a root file system and the final image. It even supports integrating supported bootloaders depending on the configuration! Neat, right!?

Additional Changes

I still needed some hacks to get it working for various reasons. First, you need to know what configuration options you need for building for RISCV64 architecture.

Config

BR2_riscv=y
BR2_JLEVEL=1
BR2_KERNEL_HEADERS_CUSTOM_TARBALL=y
BR2_KERNEL_HEADERS_CUSTOM_TARBALL_LOCATION="file:///path/to/kernel/linux-version.tar.gz"
BR2_TARGET_GENERIC_ROOT_PASSWD="password"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="file:///path/to/kernel/linux-version.tar.gz"
BR2_LINUX_KERNEL_USE_ARCH_DEFAULT_CONFIG=y
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_RISCV_PK=y

Those are the changes I had to make from the default options. Once you make your changes via make menuconfig, you can generate the above short diff with make savedefconfig. You can just copy the above file to .config and start the build, Make sure you change the path to the Linux Kernel.

An extra hack

Linux 5.0 has not been released yet, and hence buildroot does not have support for this version. But RISCV requires an unreleased version. But buildroot has an issue with a major change in the version number for the kernel. For this reason, a small patch is needed. It is not a gracious fix thought. The problem is that kernel version is 5.x and while the glibc header has its API matching version 4.18. This will not be a show stopper since Linux has backward compatibility. Apply this diff:

diff --git a/support/scripts/check-kernel-headers.sh b/support/scripts/check-kernel-headers.sh
index a8cca78b27..b36c37d6d7 100755
--- a/support/scripts/check-kernel-headers.sh
+++ b/support/scripts/check-kernel-headers.sh
@@ -29,7 +29,7 @@ int main(int argc __attribute__((unused)),
         printf("expected %d.%d.x, got %d.%d.x\n", ${HDR_M}, ${HDR_m},
                ((LINUX_VERSION_CODE>>16) & 0xFF),
                ((LINUX_VERSION_CODE>>8) & 0xFF));
-        return 1;
+        return 0;
     }
     return 0;
 }

Additional sources

As you see, I'm not using the mainline kernel, since it just does not work! It will give you a kernel panic. I used the tree maintained by Anup Patel, one of the developers working on the kernel port. It is at https://github.com/avpatel/linux

You can generate the tar.gz directly from Github. You can downlaod it with wget:

wget https://github.com/avpatel/linux/archive/master.tar.gz

Keep in mind, I am using the *local tarball* method to build the kernel since I do not want buildroot to download the whole kernel git history. So I manually downloaded in advance. If there is a better way to do it, please let me know!

Now you can go ahead and make!

Running in QEMU

Luckily, we do not need to build it on our own since the changes have been upstreamed. It is very likely that the Qemu in your distro's repo has qemu support. So install it, and just run it~

qemu-system-riscv64 -nographic -machine virt -kernel output/images/bbl   -append "console=ttyS0"     -drive file=output/images/rootfs.ext2,format=raw,id=hd0     -device virtio-blk-device,drive=hd0   -netdev user,id=net0    -device virtio-net-device,netdev=net0