-
Notifications
You must be signed in to change notification settings - Fork 53
resources: Add doc for riscv-fs-busybox-opensbi-nodisk resource #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: stable
Are you sure you want to change the base?
Changes from 1 commit
ef7547f
d5bdb87
00958ec
2cb2179
7e3abb2
b634dc8
9cb3868
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
--- | ||
title: RISC-V Full System in One Kernel Resource | ||
tags: | ||
- fullsystem | ||
- bootloader | ||
- riscv | ||
layout: default | ||
permalink: resources/riscv-fs-busybox-opensbi | ||
shortdoc: > | ||
Resources to build an OpenSBI bootloader with Linux image, initramfs and Busybox that works with gem5 full system simulations. | ||
author: ["Jonathan Kretschmer"] | ||
--- | ||
|
||
# RISC-V Linux Full System Bootloader, initramfs and Workload in One | ||
|
||
This document provides instructions to create an | ||
(OpenSBI)[https://github.com/riscv-software-src/opensbi] bootloader binary | ||
with Linux kernel image payload containing an initramfs with | ||
(Busybox)[https://www.busybox.net/] that works with gem5 full system simulations. | ||
|
||
This guide is inspired by and partly copied from | ||
(riscv-fs-nodisk)[https://github.com/gem5/gem5-resources/blob/stable/src/riscv-fs-alt/riscv-boot-exit-nodisk/README.md] | ||
and (Linux on RISC-V using QEMU and BUSYBOX from scratch)[https://risc-v-machines.readthedocs.io/en/latest/linux/simple/]. | ||
|
||
For this guide we assume following directory structure. Gem5 source itself is | ||
required either, but not listed here to avoid duplication. | ||
``` | ||
riscv-all-in-one/ | ||
├── busybox/ # busybox source | ||
├── cpio/ # contains the .cpio file | ||
├── initramfs/ # contains the structure of initramfs | ||
├── linux/ # linux source | ||
├── opensbi/ # OpenSBI source, providing a RISC-V bootloader | ||
├── riscv-gnu-toolchain/ # riscv tool chain for cross compilation | ||
└── README.md # This README file | ||
``` | ||
|
||
# Building the resource | ||
## Step 1. Building the `riscv-gnu-toolchain` | ||
In this step, we'll use | ||
[GNU toolchain for RISC-V](https://github.com/riscv-collab/riscv-gnu-toolchain). | ||
|
||
This step is necessary if you do not have basic libraries built for RISCV or | ||
if you're cross-compiling RISCV. | ||
|
||
```sh | ||
cd riscv-all-in-one/ | ||
git clone https://github.com/riscv-collab/riscv-gnu-toolchain.git | ||
cd riscv-gnu-toolchain | ||
git switch --detach 20f615317e2ce888dfc11b29ccde4a649494b654 # for reproducability, newer versions should work either | ||
mkdir build | ||
cd build | ||
# --prefix parameter specifying the installation location | ||
# --enable-multilib build either cross-compiler with support for both 32-bit and 64-bit | ||
../configure --prefix=/path/to/rvtoolchain --enable-multilib | ||
make linux -j$(nproc) | ||
``` | ||
To update the PATH environment variable so that the RISCV compilers can be | ||
found, | ||
```sh | ||
export PATH=/path/to/rvtoolchain/bin/:$PATH | ||
``` | ||
|
||
## Step 2. Getting and Building `busybox` | ||
More information about Busybox is [here](https://www.busybox.net/). | ||
```sh | ||
cd riscv-all-in-one/ | ||
git clone --branch 1_36_stable https://git.busybox.net/busybox.git # choose a stable branch | ||
|
||
# alternatively downloading tar | ||
wget https://git.busybox.net/busybox/snapshot/busybox-1_36_1.tar.bz2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume we do have to compile busybox (unlike gcc above). But can you confirm this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, Busybox is not distributing for the required RISCV platform (see their download page). Also i configure it to use no shared libraries in order to simplify the guide. |
||
tar xf busybox-1_36_1.tar.bz2 | ||
mv busybox-1_36_1 busybox | ||
|
||
cd busybox | ||
# create a default configuration | ||
make CROSS_COMPILE=riscv64-unknown-linux-gnu- defconfig | ||
make CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig | ||
# Configure static linking in order to simplify things. | ||
# Settings ---> | ||
# Build Options ---> | ||
# Build static binary (no shared libs) ---> yes | ||
make CROSS_COMPILE=riscv64-unknown-linux-gnu- all -j$(nproc) | ||
make CROSS_COMPILE=riscv64-unknown-linux-gnu- install # optional | ||
``` | ||
The files of interest are in `busybox/_install/bin`. | ||
|
||
## Step 3. Compiling the Workload (e.g. gem5's m5) | ||
Change to the directory with your clone of gem5 version 24.0.0.1. | ||
```sh | ||
cd gem5/ | ||
cd util/m5 | ||
scons build/riscv/out/m5 | ||
``` | ||
**Note**: the default cross-compiler is `riscv64-unknown-linux-gnu-`. | ||
To change the cross-compiler, you can set the cross-compiler using the scons | ||
sticky variable `riscv.CROSS_COMPILE`. For example, | ||
```sh | ||
scons riscv.CROSS_COMPILE=riscv64-linux-gnu- build/riscv/out/m5 | ||
``` | ||
|
||
## Step 4. Determining the Structure of `initramfs` | ||
Your Linux requires a *file system* in order to properly run. So we will | ||
prepare the file structure and the `init` script. | ||
```sh | ||
cd riscv-all-in-one/ | ||
mkdir initramfs | ||
cd initramfs | ||
mkdir -p {bin,sbin,dev,etc,home,mnt,proc,sys,usr,tmp} | ||
mkdir -p usr/{bin,sbin} | ||
mkdir -p proc/sys/kernel | ||
# Without following devices, we cannot see the output to `stdout` and `stderr` | ||
fakeroot -- mknod -m 622 dev/console c 5 1 | ||
fakeroot -- mknod -m 622 dev/sda b 8 0 | ||
fakeroot -- mknod -m 622 dev/tty c 5 0 | ||
fakeroot -- mknod -m 622 dev/ttyprintk c 5 3 | ||
fakeroot -- mknod -m 622 dev/null c 1 3 | ||
``` | ||
**Note:** `mknod -m 622 /dev/tty c 5 0` means we're creating `/dev/tty` with | ||
permission of `622`. `c` means a character device being created, `5` is the | ||
major number, and `0` is the minor number. More information about the | ||
major/minor numbering is available at | ||
(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/devices.txt). | ||
|
||
Drop the `busybox` executable from the previous section into the filesystem: | ||
```sh | ||
cp ../busybox/busybox ./bin/ | ||
``` | ||
Drop the workload: | ||
```sh | ||
cp /path/to/your/gem5/util/m5/build/riscv/out/m5 ./sbin/m5 # replace m5 by the desired workload | ||
``` | ||
After the kernel has started, we have to start Busybox and finalize the system | ||
initialization. We will use a script called `init` that will do the hard work, | ||
and finally starts the workload. | ||
Create `initramfs/init` script with the following content, | ||
``` | ||
#!/bin/busybox sh | ||
|
||
# Make symlinks | ||
/bin/busybox --install -s | ||
|
||
# Mount system | ||
mount -t devtmpfs devtmpfs /dev | ||
mount -t proc proc /proc | ||
mount -t sysfs sysfs /sys | ||
mount -t tmpfs tmpfs /tmp | ||
|
||
# Busybox TTY fix | ||
setsid cttyhack sh | ||
|
||
# https://git.busybox.net/busybox/tree/docs/mdev.txt?h=1_32_stable | ||
echo /sbin/mdev > /proc/sys/kernel/hotplug | ||
mdev -s | ||
|
||
# enter a shell | ||
#sh | ||
# or execute the workload | ||
/sbin/m5 exit # replace with desired workload | ||
``` | ||
Add executable flag: | ||
```sh | ||
chmod +x init | ||
``` | ||
At this stage, your initramfs should look like: | ||
```sh | ||
$ tree | ||
. | ||
├── bin | ||
│ └── busybox | ||
├── dev | ||
│ ├── console | ||
│ ├── null | ||
│ ├── sda | ||
│ ├── tty | ||
│ └── ttyprintk | ||
├── etc | ||
├── home | ||
├── init | ||
├── mnt | ||
├── proc | ||
│ └── sys | ||
│ └── kernel | ||
├── sbin | ||
│ └── m5 | ||
├── sys | ||
├── tmp | ||
└── usr | ||
├── bin | ||
└── sbin | ||
|
||
15 directories, 8 files | ||
``` | ||
To create the cpio file from the `initramfs` folder, | ||
```sh | ||
mkdir riscv-all-in-one/cpio | ||
cd riscv-all-in-one/initramfs | ||
fakeroot -- find . -print0 | cpio --owner root:root --null -o --format=newc > ../cpio/initramfs.cpio | ||
# alternatively with the tool available in the (previously build) linux kernel | ||
#../linux/usr/gen_initramfs.sh -o ../cpio/initramfs.cpio ./ | ||
lsinitramfs ../cpio/initramfs.cpio # checking the file structure of the created cpio file | ||
``` | ||
|
||
## Step 5. Compiling `Linux Kernel` with a customized `initramfs` | ||
```sh | ||
cd riscv-all-in-one/ | ||
git clone --depth 1 --branch v6.11 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git | ||
|
||
# alternatively downloading tar | ||
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.11.10.tar.xz | ||
tar xf linux-6.11.10.tar.xz | ||
mv linux-6.11.10 linux | ||
|
||
cd linux | ||
# ?? CFLAGS_KERNEL=" -march=rv64gc" | ||
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- defconfig | ||
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We should use just one cross compiler, and, unless there's a really good reason, it should be a precompiled toolchain, not one that we compile ourselves. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the initial commit the lines that referred to As i use the Debian shipped compilers now, i have to specify the toolchain prefix for |
||
# Go to "General setup --->" | ||
# Check on "Initial RAM filesystem and RAM disk (initramfs/initrd) support" | ||
# Change "Initramfs source file(s)" to the absoblute path of riscv-all-in-one/cpio/initramfs.cpio | ||
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- all -j$(nproc) | ||
``` | ||
The file of interest is at `arch/riscv/boot/Image`. | ||
|
||
## Step 6. Compiling `OpenSBI` with the Linux kernel as the payload | ||
```sh | ||
cd riscv-all-in-one/ | ||
git clone https://github.com/riscv-software-src/opensbi | ||
cd opensbi | ||
git switch --detach v1.4 | ||
make PLATFORM=generic FW_PAYLOAD_PATH=../linux/arch/riscv/boot/Image CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc) | ||
``` | ||
The desired bootloader file is at `build/platform/generic/firmware/fw_payload.elf`. | ||
|
||
# Example | ||
|
||
You can run the created bootloader with Linux and Busybox payload using the example riscv `fs_linux.py` config, | ||
```sh | ||
cd gem5 | ||
./build/RISCV/gem5.opt configs/example/riscv/fs_linux.py --kernel="../gem5-resources/src/riscv-fs/riscv-all-in-one/opensbi/build/platform/generic/firmware/fw_payload.elf" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer all examples to use the stdlib. If you could describe how to turn this into a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the hard part for me. As far as i see, only specifying a bootloader without kernel and disk image is not intended by the boards, e.g. RiscvBoard or RISCVMatchedBoard. Therefore i just show how to slightly modify the In the end it might look like # Set the Full System workload.
board.set_kernel_disk_workload(
kernel=obtain_resource(
"riscv-bootloader-vmlinux-5.10", resource_version="1.0.0"
), # dummy resource
disk_image=obtain_resource("riscv-disk-img", resource_version="1.0.0"), # dummy resource
bootloader=obtain_resource(
"riscv-fs-busybox-opensbi-nodisk", resource_version="1.0.0"
),
) |
||
``` | ||
You can check the console output with `telnet` or gem5's `m5term`, | ||
```sh | ||
telnet localhost <port> | ||
# or | ||
cd util/term | ||
make | ||
./m5term localhost <port> | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have to compile the toolchain? If there's a good reason not to use the precompiled toolchain from Ubuntu, then this step is OK, but if it's possible to use the precompiled toolchain, then we should do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be helpful if you modify the toolchain itself, however in the default case for this resource the shipped toolchain is faily enough, so i changed it to use Debian's
g++-12-riscv64-linux-gnu
package. See lines 43-74.