Riscv64: Difference between revisions
WhyNotHugo (talk | contribs) (Delete empty sections and broken links) |
No edit summary |
||
| (12 intermediate revisions by 4 users not shown) | |||
| Line 1: | Line 1: | ||
{{TOC right}} | {{TOC right}} | ||
{{Move|Running Alpine riscv64 in QEMU|Relocate this current page to one specific to QEMU. This page would then become a list of articles related to installing Alpine Linux on specific RISCV66 hardware implementations. The new location of this article would be listed on the new page. A preview of the new page can be found [[Riscv64 Redo|here]]}} | |||
riscv64 (RISC-V 64-bit) 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' | == Running Alpine riscv64 in QEMU == | ||
=== Installing QEMU on Alpine === | |||
Installing QEMU for RISC-V on Alpine is very straightforward: | |||
{{Cmd|# apk add qemu-system-riscv64 qemu-img}} | |||
You will need {{Pkg|qemu-img|arch=riscv64}} 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: | |||
{{Cmd|$ qemu-img create -f qcow2 alpine-riscv64.qcow2 2G}} | |||
Adjust the ''size'' parameter as you see fit. | |||
=== Getting U-Boot === | |||
[https://u-boot.org/ U-Boot], aka ''Das U-Boot: The Universal Boot Loader'', is one of the easiest, most flexible ways to boot Alpine on RISC-V. It can be used with GRUB for EFI booting, or with <code>extlinux.conf</code> for non-EFI booting. | |||
You need the file '''<code>u-boot.bin</code>''' to boot using U-Boot. Alpine provides a compiled <code>u-boot.bin</code> in two places: | |||
# The '''Generic U-Boot tarball''' on the [https://alpinelinux.org/downloads/ Alpine downloads page]. Currently that is: | |||
#:https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/riscv64/alpine-uboot-3.23.3-riscv64.tar.gz | |||
# The '''[https://pkgs.alpinelinux.org/package/edge/main/riscv64/u-boot-qemu <code>u-boot-qemu</code> package for <code>riscv64</code>]'''. Note that if you are not already on an Alpine riscv64 system, you won’t be able to just <code>apk add</code> this package, as it will be for a different architecture. In practical terms this means downloading the <code>.apk</code> file directly from an APK mirror, e.g.: | |||
#:https://dl-cdn.alpinelinux.org/edge/main/riscv64/u-boot-qemu-2026.01-r0.apk | |||
If you downloaded the <code>.tgz</code> file, this command will extract the <code>u-boot.bin</code> file to the current directory: | |||
{{Cmd|$ 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 <code>.apk</code> file, this command will extract the <code>u-boot.bin</code> file to the current directory: | |||
{{Cmd|$ tar --strip-components 4 -xf u-boot-qemu-2026.01-r0.apk \ | |||
usr/share/u-boot/qemu-riscv64_smode/u-boot.bin}} | |||
{{Note|There are two <code>u-boot.bin</code> files, but you need the one in the <code>qemu-riscv64_smode</code> 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).}} | |||
=== 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 [https://alpinelinux.org/downloads/ Alpine downloads page]. Here is an example of launching QEMU using U-Boot to boot this ISO: | |||
{{Cmd|$ 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: | |||
* <code>-nographic</code> will select a serial console (rather than a graphical one). | |||
* <code>-kernel u-boot.bin</code> is what causes OpenSBI to load U-Boot. | |||
* The <code>-netdev</code> and <code>-device virtio-net-device</code> lines set up ''user-mode networking'' with SSH port forwarding from the host:2222 to the guest:22. | |||
* The ISO is being treated as a <code>virtio-blk-device</code> rather than a real CD-ROM drive. | |||
* After you’ve run <code>setup-alpine</code>, 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'' <code>extlinux.conf</code>, which U-Boot will try to use first if present: | |||
{{Cmd|$ 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 <code>alpine-uboot-3.23.3-riscv64</code> as a [https://www.qemu.org/docs/master/system/images.html#virtual-fat-disk-images Virtual FAT disk image]: | |||
{{Cmd|$ 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 (<code>alpine-uboot-3.23.3-riscv64</code>). Note the <code>fat:ro:</code> syntax to emulate a virtual hard drive from a directory on the host. | |||
=== U-Boot + extlinux.conf === | |||
U-Boot can use <code>extlinux.conf</code> 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 [https://www.qemu.org/docs/master/system/images.html#virtual-fat-disk-images Virtual FAT disk image]. | |||
First, extract the Generic U-Boot tarball: | |||
{{Cmd|$ 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: | |||
{{Cmd|$ 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}} | |||
{{Warning|A [https://lists.denx.de/pipermail/u-boot/2025-August/596500.html regression exists in U-Boot 2025.10], which is included with the Alpine 3.23 release, that may prevent booting via <code>extlinux.conf</code>. 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 [https://github.com/u-boot/u-boot/commit/62f1afbe7a8ae8f8b9e85c5ea4eb446b97892a7c resolved in U-Boot 2026.01]. | |||
'''Solution:''' use the <code>u-boot.bin</code> file from the Alpine Edge build of the {{Pkg|u-boot-qemu|arch=riscv64}} package, which will be U-Boot 2026.01 or later. See the ''[[#Getting_U-Boot|Getting U-Boot]]'' section for the URL and APK extraction instructions.}} | |||
The boot path is therefore: | |||
QEMU => OpenSBI => U-Boot + extlinux.conf => Linux | |||
Some explanatory notes about the command: | |||
* <code>-nographic</code> will select a serial console (rather than a graphical one). | |||
* <code>-kernel u-boot.bin</code> is what causes OpenSBI to load U-Boot. | |||
* The <code>-netdev</code> and <code>-device virtio-net-device</code> lines set up ''user-mode networking'' with SSH port forwarding from the host:2222 to the guest:22. | |||
* After you’ve run <code>setup-alpine</code>, you can remove the last two lines on subsequent launches, so the virtual FAT disk image is no longer attached. | |||
{{Tip|You may see a usage message that begins like: | |||
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: | |||
{{Cmd|# BOOTLOADER{{=}}none setup-alpine}} | |||
}} | |||
(While it is technically possible to install from the ISO using <code>extlinux.conf</code>, doing so is more trouble than it’s worth, as you have to create a separate boot volume containing <code>/boot/vmlinuz-lts</code>, <code>/boot/initramfs-lts</code> from the ISO, and <code>/extlinux/extlinux.conf</code> from the Generic U-Boot tarball.) | |||
=== EDK2 + GRUB EFI === | |||
Using EDK2 is convenient in that it comes bundled with {{Pkg|qemu-system-riscv64|arch=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: | |||
{{Cmd|$ 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}} | |||
{{Warning|EDK2 will not boot the kernel without <code>acpi{{=}}off</code>. 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: | |||
* <code>-nographic</code> will select a serial console (rather than a graphical one). | |||
* The two <code>pflash</code> lines load two files: | |||
** the EDK2 ''code'' in <code>readonly</code> mode. | |||
** the EDK2 ''vars'' (EDK2’s nvram, essentially) in a writable way. | |||
**:(EDK2 doesn’t load via <code>-kernel</code>, unlike U-Boot.) | |||
* The <code>-netdev</code> and <code>-device virtio-net-device</code> lines set up ''user-mode networking'' with SSH port forwarding from the host:2222 to the guest:22. | |||
* After you’ve run <code>setup-alpine</code>, you can remove the last two lines on subsequent launches, so the virtual FAT disk image is no longer attached. | |||
{{Tip|EDK2 produces ''voluminous'' output before the Linux kernel starts. This is expected, even if seemingly abnormal.}} | |||
=== 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 <code>apk upgrade</code> has 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 <code>apk upgrade</code>), but the one that was present on the host when QEMU was first launched. For this reason, it’s suggested that you use the <code>-noreboot</code> QEMU option to prevent reboots. | |||
* Because there is no bootloader to pass kernel options, you must specify <code>-append</code> QEMU 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 <code>apk add {{Pkg|7zip|arch=riscv64}}</code>. | |||
{{Cat|extract.sh|extract_boot_images() { | |||
case "$1" in | |||
iso{{!}}tar) | |||
7z x -aoa "$2" boot/vmlinuz-lts boot/initramfs-lts | |||
;; | |||
hdimg) | |||
7z x -aoa "$2" 0.img | |||
7z x -aoa 0.img -oboot vmlinuz-lts initramfs-lts | |||
rm -f 0.img | |||
;; | |||
esac | |||
[ -f boot/vmlinuz-lts ] && gunzip < boot/vmlinuz-lts > boot/vmlinux-lts | |||
}}} | |||
This function takes two arguments: the file type, <code>iso</code>, <code>tar</code>, or <code>hdimg</code>, 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 <code>/boot</code>, ie, <code>/dev/vda1</code>), and then extract the images from that. In both cases, it decompresses <code>vmlinuz-lts</code> to <code>vmlinux-lts</code>, since it seems that OpenSBI wants an uncompressed kernel image. | |||
{{Note|If you extract the kernel and initramfs from the ISO, you should use the ISO to install; and similarly, if you extract them from the Generic U-Boot tarball, you should use the tarball to install.}} | |||
==== Install booting ==== | |||
Here is an example QEMU command line for installation booting (first using the shell script above to extract the images): | |||
{{Cmd|$ . 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: | |||
* <code>-nographic</code> will select a serial console (rather than a graphical one). | |||
* The <code>-kernel</code>, <code>-initrd</code>, and <code>-append</code> lines set up the kernel boot from files on the host. The <code>-append</code> string is set up for booting from install media (the ISO or tarball). | |||
* The <code>-netdev</code> and <code>-device virtio-net-device</code> lines set up ''user-mode networking'' with SSH port forwarding from the host:2222 to the guest:22. | |||
* <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 <code>setup-alpine</code> 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: | |||
{{Cmd|$ . 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 <code>-append</code> line, which specifies the virtio disk <code>/dev/vda3</code> as the <code>root</code>. | |||
Normally the <code>root</code> parameter would be a UUID. If you prefer to use a UUID, you can grab it using a command like: | |||
{{Cmd|# blkid /dev/vda3}} | |||
And update your <code>-append</code> parameter accordingly, e.g.: | |||
{{Cmd| -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 riscv64 would be with the help of an existing Alpine system (using any architecture, not just riscv64). Here are two articles that discuss this method: | |||
* [https://arvanta.net/alpine/install-alpine-riscv64-qemu/ install Alpine Linux riscv64 under qemu] | |||
* [https://arvanta.net/alpine/install-alpine-riscv64-qemu-uboot/ install Alpine Linux riscv64 under qemu with u-boot loader] | |||
{{Note|These articles were created for a previous version of Alpine, and there may be differences in the way that a current <code>setup-alpine</code> 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 [https://gitlab.alpinelinux.org/alpine/aports/-/issues/?label_name%5B%5D=arch%3Ariscv64 report] the bugs you find. | |||
* Write and improve guides about the port. | |||
* Fix [https://gitlab.alpinelinux.org/alpine/aports packages] that are buggy or don't work on RISC-V. | |||
''This section is based on [https://irclogs.alpinelinux.org/%23alpine-riscv64-2025-10.log this] [[Alpine Linux:IRC|IRC]] conversation from 2025-10-01.'' | |||
[[Category:Riscv64]] | |||
Latest revision as of 01:16, 10 April 2026
It should be renamed to Running Alpine riscv64 in QEMU. Relocate this current page to one specific to QEMU. This page would then become a list of articles related to installing Alpine Linux on specific RISCV66 hardware implementations. The new location of this article would be listed on the new page. A preview of the new page can be found here (Discuss) |
riscv64 (RISC-V 64-bit) 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 riscv64 in QEMU
Installing QEMU on Alpine
Installing QEMU for RISC-V 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. 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).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

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 the Alpine Edge build of the u-boot-qemu package, which will be U-Boot 2026.01 or later. See the Getting U-Boot section for the URL and APK extraction instructions.
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 riscv64 would be with the help of an existing Alpine system (using 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.
