Riscv64: Difference between revisions
(Added the results of my testing of the new ISO images, plus some testing of U-Boot, EDK2, and direct booting) |
m (Fixing template-breaking character escaping) |
||
| Line 3: | Line 3: | ||
RISC-V 64 is one of the [[architecture|architectures]] that Alpine Linux supports. The first stable release was Alpine Linux 3.20. Standard ISO images are available since Alpine Linux 3.23. You can download it from the [https://alpinelinux.org/downloads/ Alpine Linux downloads] page. | RISC-V 64 is one of the [[architecture|architectures]] that Alpine Linux supports. The first stable release was Alpine Linux 3.20. Standard ISO images are available since Alpine Linux 3.23. You can download it from the [https://alpinelinux.org/downloads/ Alpine Linux downloads] page. | ||
== QEMU == | == Running Alpine RISC-V 64 in QEMU == | ||
=== Installing QEMU | === Installing QEMU on Alpine === | ||
Installing QEMU on Alpine is very straightforward: | Installing QEMU for RISC-V 64 on Alpine is very straightforward: | ||
{{Cmd|# apk add qemu-system-riscv64 qemu-img}} | {{Cmd|# apk add qemu-system-riscv64 qemu-img}} | ||
| Line 136: | Line 136: | ||
{{Tip|You may see a usage message that begins like: | {{Tip|You may see a usage message that begins like: | ||
usage: /usr/sbin/update-u-boot [-b{{ | usage: /usr/sbin/update-u-boot [-b{{!}}--board <board-type>] [-d{{!}}--device <device>] | ||
This is harmless. If it concerns you, it can be suppressed during the install by using the <code>BOOTLOADER</code> environment variable: | This is harmless. If it concerns you, it can be suppressed during the install by using the <code>BOOTLOADER</code> environment variable: | ||
| Line 246: | Line 246: | ||
* <code>-noreboot</code> prevents the system from rebooting back into the installer. (You should change the command post installation so that subsequent launches boot from your hard drive image.) | * <code>-noreboot</code> prevents the system from rebooting back into the installer. (You should change the command post installation so that subsequent launches boot from your hard drive image.) | ||
Run | Run <code>setup-alpine</code> as normal. It may attempt to install a bootloader, but it won’t be used. | ||
==== Normal booting ==== | ==== Normal booting ==== | ||
Revision as of 10:36, 25 March 2026
RISC-V 64 is one of the architectures that Alpine Linux supports. The first stable release was Alpine Linux 3.20. Standard ISO images are available since Alpine Linux 3.23. You can download it from the Alpine Linux downloads page.
Running Alpine RISC-V 64 in QEMU
Installing QEMU on Alpine
Installing QEMU for RISC-V 64 on Alpine is very straightforward:
# apk add qemu-system-riscv64 qemu-img
You will need qemu-img if you want to create QCOW2 disk images; if you only want to create raw images, it’s not needed.
For example, to create a new 2 GB QCOW2 disk image:
$ qemu-img create -f qcow2 alpine-riscv64.qcow2 2G
Adjust the size parameter as you see fit.
Getting U-Boot
U-Boot, aka Das U-Boot: The Universal Boot Loader, is one of the easiest, most flexible ways to boot Alpine on RISC-V 64. It can be used with GRUB for EFI booting, or with extlinux.conf for non-EFI booting.
You need the file u-boot.bin to boot using U-Boot. Alpine provides a compiled u-boot.bin in two places:
- The Generic U-Boot tarball on the Alpine downloads page. Currently that is:
- The
u-boot-qemupackage forriscv64. Note that if you are not already on an Alpine riscv64 system, you won’t be able to justapk addthis package, as it will be for a different architecture. In practical terms this means downloading the.apkfile directly from an APK mirror, e.g.:
If you downloaded the .tgz file, this command will extract the u-boot.bin file to the current directory:
$ tar --strip-components 3 -xf alpine-uboot-3.23.3-riscv64.tar.gz \ ./u-boot/qemu-riscv64_smode/u-boot.bin
If you downloaded the .apk file, this command will extract the u-boot.bin file to the current directory:
$ tar --strip-components 4 -xf u-boot-qemu-2026.01-r0.apk \ usr/share/u-boot/qemu-riscv64_smode/u-boot.bin
u-boot.bin files, but you need the one in the qemu-riscv64_smode directory. That is because OpenSBI (the first thing QEMU executes) will run in M-mode (the highest privilege), which expects to execute U-Boot in S-mode (one privilege level lower).
extlinux.conf. The error will be similar to:
Failed to reserve memory for fdt at 0xbee9e220 FDT creation failed! hanging...### ERROR ### Please RESET the board ###
This has been resolved in U-Boot 2026.01.
Solution: use theu-boot.bin file from Alpine Edge (URL given above) APK file that has version 2026.01 or later.
U-Boot + GRUB EFI
The easiest way to run Alpine riscv64 in EFI mode is to boot from the ISO. You can download it from the Alpine downloads page. Here is an example of launching QEMU using U-Boot to boot this ISO:
$ qemu-system-riscv64 -machine virt -smp cores=2 -m 2G \ -nographic \ -kernel u-boot.bin \ -device virtio-rng-device \ -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=n0 \ -device virtio-net-device,netdev=n0 \ -drive file=alpine-riscv64.qcow2,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -drive file=alpine-standard-3.23.3-riscv64.iso,media=cdrom,if=none,id=cd0,readonly=on \ -device virtio-blk-device,drive=cd0
The boot path is therefore:
QEMU => OpenSBI => U-Boot => GRUB EFI => Linux
Some explanatory notes about the command:
-nographicwill select a serial console (rather than a graphical one).-kernel u-boot.binis what causes OpenSBI to load U-Boot.- The
-netdevand-device virtio-net-devicelines set up user-mode networking with SSH port forwarding from the host:2222 to the guest:22. - The ISO is being treated as a
virtio-blk-devicerather than a real CD-ROM drive. - After you’ve run
setup-alpine, you can remove the last two lines on subsequent launches so the ISO is no longer attached.
It’s equally possible to boot using just the Generic U-Boot tarball. First, it needs to be fully extracted, except extlinux.conf, which U-Boot will try to use first if present:
$ mkdir alpine-uboot-3.23.3-riscv64 $ tar -C alpine-uboot-3.23.3-riscv64 --exclude ./extlinux/extlinux.conf \ -xf alpine-uboot-3.23.3-riscv64.tar.gz
Then you can launch QEMU and have it emulate the alpine-uboot-3.23.3-riscv64 as a Virtual FAT disk image:
$ qemu-system-riscv64 -machine virt -smp cores=2 -m 2G \ -nographic \ -kernel u-boot.bin \ -device virtio-rng-device \ -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=n0 \ -device virtio-net-device,netdev=n0 \ -drive file=alpine-riscv64.qcow2,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -drive file=alpine-standard-3.23.3-riscv64.iso,media=cdrom,if=none,id=cd0,readonly=on \ -device virtio-blk-device,drive=hd1
This is nearly identical to the previous command, except the change from the ISO to the extracted tarball directory (alpine-uboot-3.23.3-riscv64). Note the fat:ro: syntax to emulate a virtual hard drive from a directory on the host.
U-Boot + extlinux.conf
U-Boot can use extlinux.conf to boot, which does not require EFI (and therefore does not use GRUB).
The simplest way to boot without EFI is to use the Generic U-Boot tarball. In this case, it’s extracted without modification and booted as a Virtual FAT disk image.
First, extract the Generic U-Boot tarball:
$ mkdir alpine-uboot-3.23.3-riscv64 $ tar -C alpine-uboot-3.23.3-riscv64 -xf alpine-uboot-3.23.3-riscv64.tar.gz
Then, launch QEMU:
$ qemu-system-riscv64 -machine virt -smp cores=2 -m 2G \ -nographic \ -kernel u-boot.bin \ -device virtio-rng-device \ -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=n0 \ -device virtio-net-device,netdev=n0 \ -drive file=alpine-riscv64.qcow2,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -drive file=fat:ro:alpine-uboot-3.23.3-riscv64,if=none,id=hd1,readonly=on \ -device virtio-blk-device,drive=hd1
The boot path is therefore:
QEMU => OpenSBI => U-Boot + extlinux.conf => Linux
Some explanatory notes about the command:
-nographicwill select a serial console (rather than a graphical one).-kernel u-boot.binis what causes OpenSBI to load U-Boot.- The
-netdevand-device virtio-net-devicelines set up user-mode networking with SSH port forwarding from the host:2222 to the guest:22. - After you’ve run
setup-alpine, you can remove the last two lines on subsequent launches, so the virtual FAT disk image is no longer attached.
usage: /usr/sbin/update-u-boot [-b|--board <board-type>] [-d|--device <device>]
This is harmless. If it concerns you, it can be suppressed during the install by using the BOOTLOADER environment variable:
# BOOTLOADER=none setup-alpine
(While it is technically possible to install from the ISO using extlinux.conf, doing so is more trouble than it’s worth, as you have to create a separate boot volume containing /boot/vmlinuz-lts, /boot/initramfs-lts from the ISO, and /extlinux/extlinux.conf from the Generic U-Boot tarball.)
EDK2 + GRUB EFI
Using EDK2 is convenient in that it comes bundled with qemu-system-riscv64. However, it does require a few more QEMU options than U-Boot to work successfully.
Here is an example using EDK2 to boot the Alpine riscv64 standard ISO:
$ cp /usr/share/qemu/edk2-riscv-vars.fd . $ qemu-system-riscv64 -machine virt,acpi=off -smp cores=2 -m 2G \ -nographic \ -drive if=pflash,format=raw,unit=0,file=/usr/share/qemu/edk2-riscv-code.fd,readonly=on \ -drive if=pflash,format=raw,unit=1,file=edk2-riscv-vars.fd \ -device virtio-rng-device \ -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=n0 \ -device virtio-net-device,netdev=n0 \ -drive file=alpine-riscv64.qcow2,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -drive file=alpine-standard-3.23.3-riscv64.iso,media=cdrom,if=none,id=cd0,readonly=on \ -device virtio-blk-device,drive=cd0

acpi=off. It could be that the ACPI data QEMU is providing EDK2 is not compatible or accurate, somehow.
The boot path is:
QEMU => OpenSBI => EDK2 => GRUB EFI => Linux
Some explanatory notes about the command:
-nographicwill select a serial console (rather than a graphical one).- The two
pflashlines load two files:- the EDK2 code in
readonlymode. - the EDK2 vars (EDK2’s nvram, essentially) in a writable way.
- (EDK2 doesn’t load via
-kernel, unlike U-Boot.)
- (EDK2 doesn’t load via
- the EDK2 code in
- The
-netdevand-device virtio-net-devicelines set up user-mode networking with SSH port forwarding from the host:2222 to the guest:22. - After you’ve run
setup-alpine, you can remove the last two lines on subsequent launches, so the virtual FAT disk image is no longer attached.
Direct booting
“Direct” booting means using QEMU to load the kernel and initramfs files into memory and having OpenSBI boot them directly, bypassing any other bootloader such as U-Boot, EDK2, GRUB, etc. This is a very fast method of booting, but there are some points to consider:
- You will have to somehow get the kernel and initramfs onto the host system. During installation, this is straightforward enough: you can extract them out of the installation media. But for subsequent boots (ie, after
apk upgradehas changed the kernel or initramfs in the guest), this becomes more challenging. - Reboots will not use a new kernel from within the guest (ie, one downloaded via
apk upgrade), but the one that was present on the host when QEMU was first launched. For this reason, it’s suggested that you use the-norebootQEMU option to prevent reboots. - Because there is no bootloader to pass kernel options, you must specify
-appendQEMU options instead. Fortunately these are rather standardized.
The boot path for this method is simply:
QEMU => OpenSBI => Linux
Extracting the images
To make extracting the images easier, here is a shell function you can use. It uses 7-Zip, which you can install on Alpine with apk add 7zip.
Contents of extract.sh
This function takes two arguments: the file type, iso, tar, or hdimg, and the filename itself.
For the Alpine ISO or Generic U-Boot tarball, the extraction is fairly straightforward. For hard drive images (either QCOW2 or raw), it will extract the first partition (which ought to be /boot, ie, /dev/vda1), and then extract the images from that. In both cases, it decompresses vmlinuz-lts to vmlinux-lts, since it seems that OpenSBI wants an uncompressed kernel image.
Install booting
Here is an example QEMU command line for installation booting (first using the shell script above to extract the images):
$ . extract.sh $ extract_boot_images iso alpine-standard-3.23.3-riscv64.iso $ qemu-system-riscv64 -machine virt -smp cores=2 -m 2G \ -nographic \ -kernel boot/vmlinux-lts \ -initrd boot/initramfs-lts \ -append "modules=loop,squashfs,sd-mod,usb-storage quiet" \ -device virtio-rng-device \ -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=n0 \ -device virtio-net-device,netdev=n0 \ -drive file=alpine-riscv64.qcow2,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -drive file=alpine-standard-3.23.3-riscv64.iso,media=cdrom,if=none,id=cd0,readonly=on \ -device virtio-scsi-device,id=scsi0 \ -device scsi-cd,drive=cd0,bus=scsi0.0 \ -noreboot
Some explanatory notes about the command:
-nographicwill select a serial console (rather than a graphical one).- The
-kernel,-initrd, and-appendlines set up the kernel boot from files on the host. The-appendstring is set up for booting from install media (the ISO or tarball). - The
-netdevand-device virtio-net-devicelines set up user-mode networking with SSH port forwarding from the host:2222 to the guest:22. -norebootprevents the system from rebooting back into the installer. (You should change the command post installation so that subsequent launches boot from your hard drive image.)
Run setup-alpine as normal. It may attempt to install a bootloader, but it won’t be used.
Normal booting
After the installation, you can run a normal boot by extracting the kernel and initramfs out of the hard drive image you just created:
$ . extract.sh $ extract_boot_images hdimg alpine-riscv64.qcow2 $ qemu-system-riscv64 -machine virt -smp cores=2 -m 2G \ -nographic \ -kernel boot/vmlinux-lts \ -initrd boot/initramfs-lts \ -append "root=/dev/vda3 modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4" -device virtio-rng-device \ -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=n0 \ -device virtio-net-device,netdev=n0 \ -drive file=alpine-riscv64.qcow2,if=none,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -noreboot
The main difference here is in the image extraction (done using the hard drive image rather than the installation media) and in the -append line, which specifies the virtio disk /dev/vda3 as the root.
Normally the root parameter would be a UUID. If you prefer to use a UUID, you can grab it using a command like:
# blkid /dev/vda3
And update your -append parameter accordingly, e.g.:
-append "root=UUID=2341d7cd-e050-427e-afff-94fa0db4c8c5 modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4" \
Using apk to create an image
Yet another way to create a hard drive image for Alpine on RISC-V 64 would be with the help of an existing Alpine system (any architecture, not just riscv64). Here are two articles that discuss this method:
setup-alpine deploys a new system vs the result from these scripts. However, the techniques used are still sound and may be of interest.Contribute
- Test out the port and report the bugs you find.
- Write and improve guides about the port.
- Fix packages that are buggy or don't work on RISC-V.
This section is based on this IRC conversation from 2025-10-01.