2021-09-02
updated: 2023-07-26
usual disclaimer: no one is responsible for any damage/loss by using this
script bellow will create VM disk image of Alpine Linux riscv64 to run in qemu
script is created with big help of Alpine Linux developer Carlo
size of VM disk image should be adjusted according needs and parameters for sgdisk to create partitions of the needed sizes
prerequisite on alpine linux:
qemu-openrc
util-linux or util-linux-misc
e2fsprogs
qemu-riscv64
qemu-img
losetup
blkid
sgdisk
start this before running install script
/etc/init.d/qemu-binfmt start
for other linux distros apk-tool-static could be downloaded from
https://dl-cdn.alpinelinux.org/alpine/edge/main/$ARCH/apk-tools-static-$version.apk
and unpacked with tar
$ARCH is linux host OS architecture and $version is current version
for example https://dl-cdn.alpinelinux.org/alpine/edge/main/aarch64/apk-tools-static-2.14.0-r5.apk
image file name and size could be set at wish on top of the script
#!/bin/sh
# apk add qemu-img qemu-openrc losetup blkid sgdisk e2fsprogs wget tar
set -eu
: "${DISK:=rv64-vm-mmc.img}"
: "${DISKSIZE:=500M}"
readonly SCRIPT="${0##*/}"
readonly TMPDIR="$(mktemp -dt "${SCRIPT%.*}".XXXXXX)"
readonly APK_KEY="alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub"
readonly MIRROR="http://dl-cdn.alpinelinux.org/alpine"
readonly LOOPDEV="$(losetup --find)"
readonly BOOTDEV="$LOOPDEV"p1
readonly ROOTDEV="$LOOPDEV"p2
cleanup() {
set +e
mountpoint -q "$TMPDIR"/boot && umount "$TMPDIR"/boot
mountpoint -q "$TMPDIR" && umount "$TMPDIR"
losetup --detach-all
rm -rf "$TMPDIR"
}
trap cleanup EXIT INT
rm -f $DISK
truncate -s $DISKSIZE $DISK
echo "Paritioning disk"
sgdisk --clear --set-alignment=1 \
-n 1:2048:+128MiB: -c 1:boot -A 1:set:2 \
-n 2::: -c 2:root \
"${DISK}"
echo "Creating dirs and mounting"
losetup -P "$LOOPDEV" "$DISK"
mkfs.ext4 -qL boot "$BOOTDEV"
mkfs.ext4 -qL root "$ROOTDEV"
mount -t ext4 "$ROOTDEV" "$TMPDIR"
mkdir -p "$TMPDIR"/boot
mkdir -p "$TMPDIR"/etc/apk/keys
mount -t ext4 "$BOOTDEV" "$TMPDIR"/boot
echo "Setup apk keys and repositories"
wget -qP "$TMPDIR"/etc/apk/keys https://alpinelinux.org/keys/"$APK_KEY"
printf "$MIRROR/edge/%s\n" main community testing > "$TMPDIR"/etc/apk/repositories
echo "installing base packages"
apk --allow-untrusted --root "$TMPDIR" --arch riscv64 --initdb add \
alpine-base alpine-baselayout alpine-conf kmod openrc \
dbus util-linux blkid chrony \
sysfsutils ssl_client ca-certificates-bundle alpine-keys \
ethtool e2fsprogs e2fsprogs-extra libudev-zero libudev-zero-helper \
linux-firmware-none installkernel mkinitfs \
agetty tar tzdata openssh wget sgdisk linux-edge
echo "Setting up services and inittab"
for rc in boot/bootmisc boot/hostname boot/modules boot/sysctl boot/urandom boot/networking \
sysinit/devfs sysinit/hwdrivers sysinit/mdev sysinit/modules \
shutdown/mount-ro shutdown/killprocs \
default/dbus default/chronyd default/local; do
ln -s /etc/init.d/"${rc##*/}" "$TMPDIR"/etc/runlevels/"$rc"
done
echo 'SUBSYSTEM=drm;.* root:video 660 */usr/libexec/libudev-zero-helper' >> $TMPDIR/etc/mdev.conf
echo 'SUBSYSTEM=input;.* root:input 660 */usr/libexec/libudev-zero-helper' >> $TMPDIR/etc/mdev.conf
echo "Settting boot loader"
bootuuid=$(blkid -s UUID -o value $BOOTDEV)
echo "LABEL=boot /boot ext4 auto" >> $TMPDIR/etc/fstab
rootuuid=$(blkid -s UUID -o value $ROOTDEV)
echo "creating extlinux.conf, u-boot setup"
mkdir -p "$TMPDIR"/boot/extlinux
cat > $TMPDIR/boot/extlinux/extlinux.conf<<'EOF'
TIMEOUT 50
PROMPT 1
DEFAULT edge
MENU TITLE riscv64
LABEL edge
MENU LABEL alpine linux-edge kernel
KERNEL /vmlinuz-edge
INITRD /initramfs-edge
APPEND "modules=sd-mod,usb-storage,ext4,f2fs root=/dev/vda2 rw rootwait console=ttyS0 earlycon=sbi loglevel=15"
EOF
sed -i 's/^tty1.*/tty1::respawn:\/sbin\/agetty -L 115200 tty1 linux --login-pause --autologin root --noclear/' $TMPDIR/etc/inittab
sed -i 's/^#ttyS0/ttyS0/' $TMPDIR/etc/inittab
sed -i 's/^ttyS0.*/ttyS0::respawn:\/sbin\/agetty -L 115200 ttyS0 linux --login-pause --autologin root --noclear/' $TMPDIR/etc/inittab
echo "Finished, cleaning up"
to run this image file fw_payload.elf from opensbi is needed.
it can be easily built following instructions in opensbi or u-boot
here is one I have built: https://dev.alpinelinux.org/~mps/riscv64/fw_payload.elf
run this VM with next command. Memory size, number of CPUs and other parameters could be set as needed
#!/bin/sh
: "${DISK:=rv64-vm-mmc.img}"
qemu-system-riscv64 -M virt -accel tcg \
-cpu rv64 -smp cores=2 \
-bios fw_payload.elf \
-m 512M \
-drive file=${DISK},id=hd0 -device virtio-blk,drive=hd0 \
-rtc base=utc,clock=host \
-object rng-random,filename=/dev/urandom,id=rng0 \
-device virtio-rng,rng=rng0 \
-netdev user,id=n1 -device virtio-net-pci,netdev=n1 \
-nographic