Skip to content

Commit 762e4ed

Browse files
committed
Support mounting rootfs from virtio-blk via initrd
Due to the 1 GiB kernel space limit on RV32-Linux, embedding large root filesystems in the kernel image can be impractical for certain testing scenarios. This commit introduces a script to generate a mountable ext4 rootfs image and modifies the init script to support switching the root filesystem to a virtio-blk device. During boot, the init script checks whether /dev/vda contains a valid rootfs. If so, it switches the root to the virtio-blk device. Otherwise, it falls back to the default initramfs.
1 parent d26f0dd commit 762e4ed

File tree

4 files changed

+224
-8
lines changed

4 files changed

+224
-8
lines changed

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,56 @@ You can exit the emulator using: \<Ctrl-a x\>. (press Ctrl+A, leave it, afterwar
9090
An automated build script is provided to compile the RISC-V cross-compiler, Busybox, and Linux kernel from source.
9191
Please note that it only supports the Linux host environment.
9292

93+
To build everything, simply run:
94+
9395
```shell
9496
$ make build-image
9597
```
9698

99+
This command invokes the underlying script: `scripts/build-image.sh`, which also offers more flexible usage options.
100+
101+
### Script Usage
102+
103+
```
104+
./scripts/build-image.sh [--buildroot] [--linux] [--all] [--external-root] [--clean-build] [--help]
105+
106+
Options:
107+
--buildroot Build Buildroot rootfs
108+
--linux Build Linux kernel
109+
--all Build both Buildroot and Linux
110+
--external-root Use external rootfs instead of initramfs
111+
--clean-build Remove entire buildroot/ and/or linux/ directories before build
112+
--help Show this message
113+
```
114+
115+
### Examples
116+
117+
Build the Linux kernel only:
118+
119+
```
120+
$ scripts/build-image.sh --linux
121+
```
122+
123+
Build Buildroot only:
124+
125+
```
126+
$ scripts/build-image.sh --buildroot
127+
```
128+
129+
Build Buildroot and generate an external root file system (ext4 image):
130+
131+
```
132+
$ scripts/build-image.sh --buildroot --external-root
133+
```
134+
135+
Force a clean build:
136+
137+
```
138+
$ scripts/build-image.sh --all --clean-build
139+
$ scripts/build-image.sh --linux --clean-build
140+
$ scripts/build-image.sh --buildroot --clean-build
141+
```
142+
97143
## License
98144

99145
`semu` is released under the MIT License.

scripts/build-image.sh

Lines changed: 112 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,31 @@ function OK
1919

2020
PARALLEL="-j$(nproc)"
2121

22+
function safe_copy {
23+
local src="$1"
24+
local dst="$2"
25+
26+
if [ ! -f "$dst" ]; then
27+
echo "Copying $src -> $dst"
28+
cp -f "$src" "$dst"
29+
else
30+
echo "$dst already exists, skipping copy"
31+
fi
32+
}
33+
2234
function do_buildroot
2335
{
24-
ASSERT git clone https://github.com/buildroot/buildroot -b 2024.11.1 --depth=1
25-
cp -f configs/buildroot.config buildroot/.config
26-
cp -f configs/busybox.config buildroot/busybox.config
36+
if [ ! -d buildroot ]; then
37+
echo "Cloning Buildroot..."
38+
ASSERT git clone https://github.com/buildroot/buildroot -b 2024.11.1 --depth=1
39+
else
40+
echo "buildroot/ already exists, skipping clone"
41+
fi
42+
43+
safe_copy configs/buildroot.config buildroot/.config
44+
safe_copy configs/busybox.config buildroot/busybox.config
45+
cp -f target/init buildroot/fs/cpio/init
46+
2747
# Otherwise, the error below raises:
2848
# You seem to have the current working directory in your
2949
# LD_LIBRARY_PATH environment variable. This doesn't work.
@@ -32,13 +52,28 @@ function do_buildroot
3252
ASSERT make olddefconfig
3353
ASSERT make $PARALLEL
3454
popd
35-
cp -f buildroot/output/images/rootfs.cpio ./
55+
56+
if [[ $EXTERNAL_ROOT -eq 1 ]]; then
57+
echo "Copying rootfs.cpio to rootfs_full.cpio (external root mode)"
58+
cp -f buildroot/output/images/rootfs.cpio ./rootfs_full.cpio
59+
ASSERT ./scripts/rootfs_ext4.sh
60+
else
61+
echo "Copying rootfs.cpio to rootfs.cpio (initramfs mode)"
62+
cp -f buildroot/output/images/rootfs.cpio ./rootfs.cpio
63+
fi
3664
}
3765

3866
function do_linux
3967
{
40-
ASSERT git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git -b linux-6.12.y --depth=1
41-
cp -f configs/linux.config linux/.config
68+
if [ ! -d linux ]; then
69+
echo "Cloning Linux kernel..."
70+
ASSERT git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git -b linux-6.12.y --depth=1
71+
else
72+
echo "linux/ already exists, skipping clone"
73+
fi
74+
75+
safe_copy configs/linux.config linux/.config
76+
4277
export PATH="$PWD/buildroot/output/host/bin:$PATH"
4378
export CROSS_COMPILE=riscv32-buildroot-linux-gnu-
4479
export ARCH=riscv
@@ -49,5 +84,74 @@ function do_linux
4984
popd
5085
}
5186

52-
do_buildroot && OK
53-
do_linux && OK
87+
function show_help {
88+
cat << EOF
89+
Usage: $0 [--buildroot] [--linux] [--all] [--external-root] [--clean-build] [--help]
90+
91+
Options:
92+
--buildroot Build Buildroot rootfs
93+
--linux Build Linux kernel
94+
--all Build both Buildroot and Linux
95+
--external-root Use external rootfs instead of initramfs
96+
--clean-build Remove entire buildroot/ and/or linux/ directories before build
97+
--help Show this message
98+
EOF
99+
exit 1
100+
}
101+
102+
BUILD_BUILDROOT=0
103+
BUILD_LINUX=0
104+
EXTERNAL_ROOT=0
105+
CLEAN_BUILD=0
106+
107+
while [[ $# -gt 0 ]]; do
108+
case "$1" in
109+
--buildroot)
110+
BUILD_BUILDROOT=1
111+
;;
112+
--linux)
113+
BUILD_LINUX=1
114+
;;
115+
--all)
116+
BUILD_BUILDROOT=1
117+
BUILD_LINUX=1
118+
;;
119+
--external-root)
120+
EXTERNAL_ROOT=1
121+
;;
122+
--clean-build)
123+
CLEAN_BUILD=1
124+
;;
125+
--help|-h)
126+
show_help
127+
;;
128+
*)
129+
echo "Unknown option: $1"
130+
show_help
131+
;;
132+
esac
133+
shift
134+
done
135+
136+
if [[ $BUILD_BUILDROOT -eq 0 && $BUILD_LINUX -eq 0 ]]; then
137+
echo "Error: No build target specified. Use --buildroot, --linux, or --all."
138+
show_help
139+
fi
140+
141+
if [[ $CLEAN_BUILD -eq 1 && $BUILD_BUILDROOT -eq 1 && -d buildroot ]]; then
142+
echo "Removing buildroot/ for clean build..."
143+
rm -rf buildroot
144+
fi
145+
146+
if [[ $CLEAN_BUILD -eq 1 && $BUILD_LINUX -eq 1 && -d linux ]]; then
147+
echo "Removing linux/ for clean build..."
148+
rm -rf linux
149+
fi
150+
151+
if [[ $BUILD_BUILDROOT -eq 1 ]]; then
152+
do_buildroot && OK
153+
fi
154+
155+
if [[ $BUILD_LINUX -eq 1 ]]; then
156+
do_linux && OK
157+
fi

scripts/rootfs_ext4.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/bash
2+
3+
ROOTFS_CPIO="rootfs_full.cpio"
4+
IMG="ext4.img"
5+
IMG_SIZE=$((1024 * 1024 * 1024)) # 1GB
6+
IMG_SIZE_BLOCKS=$((${IMG_SIZE} / 4096)) # IMG_SIZE / 4k
7+
8+
DIR=rootfs
9+
10+
echo "[*] Remove old rootfs directory..."
11+
rm -rf $DIR
12+
mkdir -p $DIR
13+
14+
echo "[*] Extract CPIO"
15+
pushd $DIR
16+
cpio -idmv < ../$ROOTFS_CPIO
17+
popd
18+
19+
echo "[*] Create empty image"
20+
dd if=/dev/zero of=${IMG} bs=4k count=${IMG_SIZE_BLOCKS}
21+
22+
echo "[*] Create ext4 rootfs image"
23+
fakeroot mkfs.ext4 -F ${IMG} -d $DIR
24+
25+
# Show image size
26+
du -h ${IMG}

target/init

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/sh
2+
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
3+
4+
ROOTFS_DEV=/dev/vda
5+
6+
mount -t devtmpfs devtmpfs /dev
7+
mount -t proc none /proc
8+
mount -t sysfs none /sys
9+
10+
# use the /dev/console device node from devtmpfs if possible to not
11+
# confuse glibc's ttyname_r().
12+
# This may fail (e.g., booted with console=), and errors from exec will
13+
# terminate the shell, so use a subshell for the test
14+
if (exec 0</dev/console) 2>/dev/null; then
15+
exec 0</dev/console
16+
exec 1>/dev/console
17+
exec 2>/dev/console
18+
fi
19+
20+
echo "[*] Attempting to mount $ROOTFS_DEV"
21+
mkdir -p /mnt
22+
23+
mount -t ext4 $ROOTFS_DEV /mnt
24+
if [ $? -ne 0 ]; then
25+
echo "[!] Failed to mount $ROOTFS_DEV. Using initramfs."
26+
exec /sbin/init "$@"
27+
fi
28+
29+
echo "[*] $ROOTFS_DEV mounted successfully. Checking for root filesystem..."
30+
if [ -x /mnt/sbin/init ]; then
31+
echo "[*] Valid root filesystem found. Switching root to $ROOTFS_DEV"
32+
mount --move /sys /mnt/sys
33+
mount --move /proc /mnt/proc
34+
mount --move /dev /mnt/dev
35+
exec switch_root -c /dev/console /mnt /sbin/init "$@"
36+
else
37+
echo "[!] No valid root filesystem found on $ROOTFS_DEV. Using initramfs."
38+
umount /mnt
39+
exec /sbin/init "$@"
40+
fi

0 commit comments

Comments
 (0)