This documents a from-scratch install of Arch POWER Linux distribution on a pseries QEMU/KVM
VM running on a POWER9 host, with a PReP boot partition and GRUB
(powerpc-ieee1275 target). It also captures every pitfall hit along the way —
each one cost real debugging time, so they're called out explicitly rather than
silently avoided.
Endianness note: this was run and verified end-to-end on powerpc64 (big-endian).
Arch POWER also publishes a powerpc64le (little-endian)
repo, and everywhere the two variants diverge is called out inline below —
but only the big-endian path has actually been executed. The Open
Firmware/PReP/GRUB mechanics (sections 0, 2's boot-order handling, 3, and
most of 4) are endianness-agnostic and should carry over unchanged; the
places that differ are the install ISO and the kernel package name/files,
both flagged where they come up.
PowerPC installs are unusually fragile compared to x86/UEFI mainly because
there's no BIOS/UEFI boot menu convenience. The firmware is Open Firmware
(SLOF under QEMU pseries), which boots from a raw PReP partition
containing GRUB's core.img directly — no ESP, no bootloader search
heuristics like UEFI has. grub-install targeting and boot-order handling
are correspondingly stricter and less forgiving of mistakes (see the
pitfalls below).
Everything else in this guide is identical between the two; only the items in this table differ. Refer back to it wherever a step says "(see 1.1)".
Big-endian powerpc64 (verified) |
Little-endian powerpc64le (unverified) |
|
|---|---|---|
| Package repo | https://repo.archlinuxpower.org/base/powerpc64/ |
https://repo.archlinuxpower.org/base/powerpc64le/ |
| Install ISO | archpower-current-powerpc64.iso |
not checked — find the matching ISO on the project's download page |
| Kernel package | linux-ppc64 (64KB pages, the only page size offered on the BE repo) |
linux (64KB pages — matches BE, and the better choice unless you have a specific reason not to) or linux-4k (4KB pages — an alternative build for compatibility with software/guests that assume 4KB pages; pick only if you know you need it) |
| Kernel image | /boot/vmlinuz-linux-ppc64 |
/boot/vmlinuz-linux |
| Initramfs image | /boot/initramfs-linux-ppc64.img |
/boot/initramfs-linux.img |
- Disk: 50GB is comfortable and is what this guide uses. Layout:
vda1— 9 MiB, PReP boot partition (no filesystem)vda2— ~43 GiB, ext4, rootvda3— ~7 GiB, swap
- VM specs used:
- libvirt/QEMU,
machine='pseries-10.2',arch='ppc64le'(this is just QEMU's emulation target binary — it runs big-endian or little-endian ppc64 guest kernels equally; guest endianness is a kernel property, not a hypervisor one) cpu mode='custom' model='POWER9'- 8 vCPUs, 8GiB RAM
- Disk:
virtio-blk(bus='virtio'), backed by a qcow2 image - Install media: attached as a
scsicdrom (virtio-scsicontroller) - NIC:
virtiomodel (<interface type='network'><model type='virtio'/></interface>, attached to libvirt's default NAT network/virbr0). Usevirtiohere rather than an emulated NIC (e.g.e1000/rtl8139) — it's what QEMU'spseriesmachine expects for good throughput, and it's what shows up guest-side as anenp*-style interface, which is why thesystemd-networkdmatch in 4.7 usesName=en*. - A serial console is essential:
<serial type='pty'><target type='spapr-vio-serial'/></serial>. This is your only way to interact with the SLOF firmware and the GRUB shell — there's no graphical framebuffer to fall back on. Access it withvirsh console <domain>(needs a real pty — allocate one withssh -ttif you're driving this over SSH, or run it in a local terminal).
- libvirt/QEMU,
- Download the Arch Linux POWER installer ISO matching your target
endianness (see 1.1) from the Arch Linux POWER project. This guide uses
archpower-current-powerpc64.iso(big-endian); if you're doing apowerpc64leinstall, get the matching little-endian ISO instead. - Attach the ISO to the VM as a cdrom device with
<boot order='1'/>, ahead of the disk (<boot order='2'/>on thevirtiodisk). - Start the VM and attach to the console:
SLOF will boot the ISO (order 1 wins), landing you in the Arch Linux POWER live/installer environment.virsh start <domain> virsh console <domain>
Pitfall #1 — the VM never boots your install, only the ISO. If the cdrom keeps
<boot order='1'/>after you've finished installing, every reboot will land you back in the live installer, forever, regardless of whether your disk install is correct. This is easy to not notice, because the live environment looks similar enough to a real login prompt that you can spend a long time debugging GRUB when the actual problem is "the VM never even tried the disk." Fix: once install is done, either detach the cdrom device entirely, or set its boot order below the disk's.
From inside the live environment, partition the target disk (assume /dev/vda):
fdisk /dev/vda
g— create a new empty GPT partition tablen— new partition 1, size+9M(a PReP partition needs to be small; a handful of MB is plenty for GRUB'score.img)t— change its type; search for "PowerPC PReP boot" and select it
n— new partition 2, most of the remaining space, default type (Linux filesystem)n— new partition 3, remaining space for swapt— set its type to Linux swap
w— write the table
Format:
mkfs.ext4 /dev/vda2
mkswap /dev/vda3
swapon /dev/vda3
Pitfall #2 (avoided, but worth stating) — do not put a filesystem on the PReP partition. It's not mounted; GRUB writes its raw
core.imgELF blob directly onto the block device duringgrub-install.mkfs'ing it will just get overwritten and confuses nothing — but don't bother, and don't try to mount it.
Mount the root partition and pacstrap into it:
mount /dev/vda2 /mnt
Sanity-check the result with lsblk before moving on — the PARTTYPE
column is worth including since it's the actual GUID GRUB/SLOF look for to
identify the PReP partition (9e1a2d38-c612-4316-aa26-8b49521e5a8b), not
just its human-readable name:
lsblk -o NAME,SIZE,TYPE,FSTYPE,PARTTYPE,PARTLABEL,MOUNTPOINT /dev/vda
Expected output:
NAME SIZE TYPE FSTYPE PARTTYPE PARTLABEL MOUNTPOINT
vda 50G disk
├─vda1 9M part 9e1a2d38-c612-4316-aa26-8b49521e5a8b
├─vda2 42.8G part ext4 0fc63daf-8483-4772-8e79-3d69d8477de4 /mnt
└─vda3 7.1G part swap 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f
Confirm before continuing: vda1 has no FSTYPE (correct — it's meant
to stay raw), vda2 shows ext4 and is mounted at /mnt, and vda3 shows
swap (it doesn't need a MOUNTPOINT — swap is activated, not mounted).
Use the kernel package name for your target from 1.1:
# big-endian (powerpc64):
pacstrap -K /mnt base base-devel linux-ppc64 linux-firmware grub openssh vim sudo
# little-endian (powerpc64le):
pacstrap -K /mnt base base-devel linux linux-firmware grub openssh vim sudo
Pitfall #3 —
basedoes not include a kernel. This has been Arch policy since ~2012 on every architecture:basedeliberately excludes the kernel so you choose one explicitly (linux,linux-lts,linux-zen, etc). On the big-endian PowerPC port, the equivalent package islinux-ppc64; onpowerpc64leit's plainlinux— neither islinuxon the BE side, and neither is pulled in automatically. Forgetting it produces a system that installs and pacstraps fine, boots to agrub>prompt or nothing at all, and has an empty/bootexcept for GRUB's own files. There is no warning for this at install time — it only surfaces when you try to boot.
genfstab -U /mnt >> /mnt/etc/fstab
arch-chroot /mnt
Pitfall #4 — use
arch-chroot, not plainchroot. Plainchrootdoes not bind-mount/dev,/proc,/sysinto the target. Things that look unrelated break as a result — e.g.sshdfailing immediately withCould not open /dev/nullbecause/devinside the chroot is empty.arch-chroot(fromarch-install-scripts, present on the live ISO) handles all of this for you, plus copiesresolv.confso DNS works inside the chroot.
echo archpower > /etc/hostname
passwd # set root password
useradd -m -G wheel -s /bin/bash tle
passwd tle
echo '%wheel ALL=(ALL:ALL) ALL' > /etc/sudoers.d/wheel
Authorize your SSH key for the new user:
mkdir -p /home/tle/.ssh
echo '<your public key>' >> /home/tle/.ssh/authorized_keys
chown -R tle:tle /home/tle/.ssh
chmod 700 /home/tle/.ssh
chmod 600 /home/tle/.ssh/authorized_keys
echo 'KEYMAP=us' > /etc/vconsole.conf
Pitfall #5 — missing
/etc/vconsole.confbreaksmkinitcpio. Thesd-vconsolebuild hook errors out (file not found: '/etc/vconsole.conf') if this file doesn't exist yet whenmkinitcpioruns (which happens automatically as a post-install hook the moment you install the kernel package). The initramfs is still generated, but the build reports failure, which is alarming and easy to mistake for something more serious. Create the file before installing the kernel, or just rerunmkinitcpio -Pafterward once it exists.
If you installed the kernel before creating this file, just rebuild:
mkinitcpio -P
Confirm the kernel and initramfs actually exist:
ls -la /boot
# BE (linux-ppc64): grub/ initramfs-linux-ppc64.img vmlinuz-linux-ppc64
# LE (linux): grub/ initramfs-linux.img vmlinuz-linux
Edit /etc/default/grub and uncomment:
GRUB_TERMINAL_OUTPUT=console
Pitfall #6 — GRUB defaults to
gfxterm, which has no video driver on this firmware. The default/etc/default/grubleavesGRUB_TERMINAL_OUTPUTcommented out, which means GRUB tries a graphical menu (gfxterm,GRUB_GFXMODE=auto). SLOF's serial console (spapr-vty) has no framebuffer GRUB can drive, sogrub.cfg's attempt to set a video mode fails with:error: video/video.c:grub_video_set_mode:782: no suitable video mode foundThis aborts script execution before the boot menu ever displays, dropping you into an interactive
grub>shell instead — which looks like a totally broken install, but is just this one setting. Forcingconsoleoutput avoids it entirely.
grub-mkconfig -o /boot/grub/grub.cfg
grub-install --target=powerpc-ieee1275 --boot-directory=/boot /dev/vda1
Pitfall #7 — target the PReP partition, not the whole disk.
grub-install --target=powerpc-ieee1275 --boot-directory=/boot /dev/vda(the whole disk) fails with:grub-install: error: the chosen partition is not a PReP partition.Unlike a BIOS/MBR install (where you point
grub-installat the whole disk and it writes to the MBR gap), a PReP install writes GRUB'score.imgdirectly into the PReP partition itself. Pointgrub-installat the partition device (/dev/vda1), not the disk (/dev/vda).
You should see:
Installing for powerpc-ieee1275 platform.
Installation finished. No error reported.
base/base-devel doesn't include a DHCP client (dhcpcd isn't pulled in
by default). Since systemd is already there as your init system, use
systemd-networkd instead of installing anything extra:
mkdir -p /etc/systemd/network
cat > /etc/systemd/network/20-wired.network <<'EOF'
[Match]
Name=en* eth*
[Network]
DHCP=yes
EOF
systemctl enable systemd-networkd
systemctl enable systemd-resolved
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
(Check ip link for your actual interface name and adjust the Name= glob
if it doesn't match en*/eth*.)
Note — benign warning:
systemd-networkdmay logCould not set hostname: Access deniedon startup. This is expected: the shippedsystemd-networkd.serviceunit sandboxes withProtectHostname=yesby default, which blocks it from applying a hostname received via DHCP option 12. It does not affect actual address/route assignment — confirm withnetworkctl status/ip ainstead of worrying about that log line.
ssh-keygen -A
systemctl enable sshd
If you need a non-default port, add Port <N> to /etc/ssh/sshd_config
before enabling the service.
Exit the chroot, unmount, detach the install ISO (or demote its boot order below the disk — see Pitfall #1), and restart the VM:
exit
umount -R /mnt
Then, from the host (not the VM):
virsh detach-disk <domain> <cdrom-target> --config --live
virsh destroy <domain>
virsh start <domain>
Watch the console — you should see: SLOF → PReP partition → GRUB (a real text menu, no crash) → kernel boot → login prompt, all without manual intervention.
If you ever do end up at an interactive grub> prompt, these are the
commands that got a manual boot working while diagnosing the above:
grub> insmod part_gpt
grub> insmod ext2
grub> ls
GRUB names disks by Open Firmware device path, not hd0-style BIOS names —
expect something like (ieee1275/disk) (ieee1275/disk,gpt1) (ieee1275/disk,gpt2) (ieee1275/disk,gpt3).
Find your root and boot manually:
grub> ls (ieee1275/disk,gpt2)/boot/
grub> linux (ieee1275/disk,gpt2)/boot/vmlinuz-linux-ppc64 root=UUID=<your-root-uuid> rw
grub> initrd (ieee1275/disk,gpt2)/boot/initramfs-linux-ppc64.img
grub> boot
(Substitute vmlinuz-linux/initramfs-linux.img per 1.1 if you're on
powerpc64le.)
Or, to test whether grub.cfg itself is reachable/valid without going
through the full normal auto-boot flow:
grub> set root=(ieee1275/disk,gpt2)
grub> configfile (ieee1275/disk,gpt2)/boot/grub/grub.cfg
Useful if you need to check a running (or hung) VM's filesystem contents
without powering it off — e.g. to confirm whether a kernel is actually
present. qemu-nbd can attach a disk image read-only even while the VM's
own QEMU process still holds it open, by disabling image locking explicitly
(the image is opened read-only, so this is safe):
modprobe nbd max_part=8
qemu-nbd --read-only -c /dev/nbd0 \
--image-opts driver=qcow2,file.driver=file,file.filename=/path/to/disk.qcow2,file.locking=off
partprobe /dev/nbd0
mount -o ro,noload /dev/nbd0p2 /mnt/check # noload skips journal replay on a dirty fs
# ... inspect ...
umount /mnt/check
qemu-nbd -d /dev/nbd0
(-o ro,noload matters if the filesystem has a dirty/pending journal from
a live chroot session — a plain -o ro mount can be refused outright.)
| Symptom | Root cause | Fix |
|---|---|---|
| Every reboot re-launches the installer | Cdrom has boot order ahead of disk in libvirt XML | Detach ISO or demote its boot order |
/boot empty except grub/, nothing boots |
base doesn't include a kernel package |
pacman -S linux-ppc64 (BE) / linux (LE), then mkinitcpio -P |
mkinitcpio reports failure |
/etc/vconsole.conf missing |
Create it before building the initramfs |
grub-install: chosen partition is not a PReP partition |
Targeted the whole disk instead of the PReP partition | grub-install ... /dev/vda1, not /dev/vda |
GRUB drops to grub> shell, no menu |
gfxterm fails (no suitable video mode found) — no framebuffer on serial-only firmware |
GRUB_TERMINAL_OUTPUT=console in /etc/default/grub, regenerate config |
dhcpcd: command not found |
Not part of a minimal base install |
Use systemd-networkd (already present) instead |
sshd: Could not open /dev/null |
Used plain chroot instead of arch-chroot |
Re-enter with arch-chroot, which bind-mounts /dev, /proc, /sys |
SSH Host key verification failed after a fresh boot |
New host keys generated by ssh-keygen -A each session |
ssh-keygen -R <host> to clear the stale cached key |