Prerequisites:
- A PC with a Linux distribution - Arch Linux
amd64
used here
Dependencies (for Arch Linux amd64
but very easy to get on most distros):
edk2-armvirt
(or a prebuilt firmware binary from the Unofficial EDK2 nightly build project)qemu-arch-extra
(provides the commandqemu-system-aarch64
)wget
(or any downloader)gvim
(or any editor)openssh
(or QEMU console)
- Download the Arch Linux ARM generic tarball and create an image, replacing
60G
with your desired maximum size.
wget http://os.archlinuxarm.org/os/ArchLinuxARM-aarch64-latest.tar.gz
qemu-img create -f qcow2 arch-aarch64.qcow2 60G
Tip
Step 1 equivalent for Debian guest:
wget https://cdimage.debian.org/cdimage/release/current/arm64/iso-dvd/debian-12.7.0-arm64-DVD-1.iso
wget https://cdimage.debian.org/cdimage/release/current/arm64/iso-dvd/SHA256SUMS
shasum -a 256 --ignore-missing -c SHA256SUMS
qemu-img create -f qcow2 debian-aarch64.qcow2 60G
Users of Debian guest should now skip to step 7.
- Become
root
, connect the image tonbd
and partition it withfdisk
.
sudo modprobe nbd
sudo qemu-nbd --connect=/dev/nbd0 arch-aarch64.qcow2
sudo fdisk /dev/nbd0
- then
g
(to create a new GPT partition table) - then
n
(to create a new partition), then Enter twice, then+400M
and Enter - then
t
(to change the type), then1
for EFI System Partition - then
n
and Enter three times, thenw
to write changes and exit
- Format the partitions of the image, mount them, and extract the Arch Linux ARM tarball to them.
sudo mkfs.vfat /dev/nbd0p1
sudo mkfs.ext4 /dev/nbd0p2
sudo mkdir rootfs
sudo mount /dev/nbd0p2 rootfs
sudo mkdir rootfs/boot
sudo mount /dev/nbd0p1 rootfs/boot
sudo bsdtar -xpf ArchLinuxARM-aarch64-latest.tar.gz -C rootfs
- Edit
fstab
.
- You will need both partitions' UUIDs - the UUID of the
vfat
partition in/dev/nbd0p1
looks likeUUID="XXXX-XXXX"
and the UUID of theext4
partition in/dev/nbd0p2
looks likeUUID="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
:
sudo blkid
- Then, edit
rootfs/etc/fstab
:
sudo vim rootfs/etc/fstab
- Paste the following, replacing each instance of
X
with the corresponding digit of the UUID of the corresponding partition,/dev/nbd0p1
and/dev/nbd0p2
respectively, then save the file:
/dev/disk/by-uuid/XXXX-XXXX /boot vfat defaults 0 0
/dev/disk/by-uuid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX / ext4 defaults 0 0
- Create
startup.nsh
, which is read by the UEFI firmware to initially boot.
- Edit
rootfs/boot/startup.nsh
:
sudo vim rootfs/boot/startup.nsh
- Paste the following, replacing each instance of
X
with the corresponding digit of the UUID of the/dev/nbd0p2
partition, then save the file:
Image root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw initrd=\initramfs-linux.img
- Unmount the partitions,
sync
, disconnect the image fromnbd
, and exit theroot
shell.
sudo umount -R rootfs
sudo sync
sudo qemu-nbd --disconnect /dev/nbd0
sudo rmmod nbd
- Create flash images for the UEFI firmware and variables
Note
if you downloaded the RELEASEAARCH64_QEMU_EFI.fd
instead of using the one from your distro's package, use that here in place of the QEMU_CODE.fd
. AARCH64_QEMU_EFI.fd
s (which are installed into "flash0.img
" here) can very slowly become slightly outdated over time. After using one with an Arch Linux ARM emulator for several years, then installing a new emulator from scratch and comparing its behavior with the old one, I've noticed very slight, subtle differences in behavior between them in the pre-boot stage before guest OS code runs. I would say the newer one's behavior seems slightly more polished and desirable.
truncate -s 64M flash0.img
truncate -s 64M flash1.img
dd if=/usr/share/edk2-armvirt/aarch64/QEMU_CODE.fd of=flash0.img conv=notrunc
- Launch QEMU, removing or adding anything you see fit.
qemu-system-aarch64 -M virt -m 8192 -cpu cortex-a72 -smp 8 \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash0.img \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash1.img \
-drive if=none,file=arch-aarch64.qcow2,format=qcow2,id=hd0 \
-device virtio-scsi-pci,id=scsi0 \
-device scsi-hd,bus=scsi0.0,drive=hd0,bootindex=1 \
-nic user,model=virtio-net-pci,hostfwd=tcp::2222-:22 \
-monitor none -display none -vga none
Tip
Step 8 equivalent for Debian guest:
qemu-system-aarch64 -M virt -m 8192 -cpu cortex-a72 -smp 8 \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash0.img \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash1.img \
-drive if=none,file=debian-aarch64.qcow2,format=qcow2,id=hd0 \
-cdrom debian-12.7.0-arm64-DVD-1.iso \
-device virtio-scsi-pci,id=scsi0 \
-device scsi-hd,bus=scsi0.0,drive=hd0,bootindex=2 \
-nic user,model=virtio-net-pci,hostfwd=tcp::2222-:22 \
-nographic
- Upon successful first boot, initialize Arch Linux ARM and install a new bootloader.
- Log in as
alarm
, passwordalarm
:
ssh -p 2222 alarm@localhost
- Become
root
, passwordroot
:
su
- Initialize the
pacman
keyring, update the system and installefibootmgr
, replacing each instance ofX
with the corresponding digit of the UUID of the/dev/nbd0p2
partition from earlier (which is now/dev/sda2
), then shut down:
pacman-key --init
pacman-key --populate archlinuxarm
pacman -Syu
pacman -S efibootmgr
efibootmgr --disk /dev/sda --part 1 --create --label "Arch Linux ARM" --loader /Image --verbose \
--unicode 'root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw initrd=\initramfs-linux.img'
poweroff
Tip
Step 9 equivalent for Debian guest:
- At the EDK II Shell, type this command
FS1:\efi\boot\grubaa64.efi
Users of Debian guest can choose "Install" and use the guided installer.
- Launch QEMU again, exactly as in step 8.
qemu-system-aarch64 -M virt -m 8192 -cpu cortex-a72 -smp 8 \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash0.img \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash1.img \
-drive if=none,file=arch-aarch64.qcow2,format=qcow2,id=hd0 \
-device virtio-scsi-pci,id=scsi0 \
-device scsi-hd,bus=scsi0.0,drive=hd0,bootindex=1 \
-nic user,model=virtio-net-pci,hostfwd=tcp::2222-:22 \
-monitor none -display none -vga none
Tip
Step 10 equivalent for Debian guest:
qemu-system-aarch64 -M virt -m 8192 -cpu cortex-a72 -smp 8 \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash0.img \
-drive if=pflash,media=disk,format=raw,cache=writethrough,file=flash1.img \
-drive if=none,file=debian-aarch64.qcow2,format=qcow2,id=hd0 \
-device virtio-scsi-pci,id=scsi0 \
-device scsi-hd,bus=scsi0.0,drive=hd0,bootindex=2 \
-nic user,model=virtio-net-pci,hostfwd=tcp::2222-:22 \
-nographic
- Proceed with configuring Arch Linux ARM as normal (time, locales, users, software, configuration), using the Arch Linux Wiki as a guide.
Note
If your host has a simple network configuration, you can replace the slower -nic user
argument with an efficient -netdev tap
argumnet if you want using my minimal tap0
guide.
Fantastic tutorial.
I did not understood the passage 7, what it does?