Table of contents:
You’ll need only two things to start:
Note that this guide leverages user mode networking extensively. If you prefer to use bridging or some other network configuration, you could refer to the ppc64le installation instructions on the Alpine Wiki.
Before beginning, it might be a good idea to check that your QEMU is working. Just do something like:
$ qemu-system-ppc64 -version QEMU emulator version 8.2.1 Copyright (c) 2003-2023 Fabrice Bellard and the QEMU Project developers
Your virtual hard disk will require space for a PPC PReP boot partition, a /boot partition, a root partition (/), and a swap partition. The total install takes about 400 MB, but you’ll probably want to leave space for future growth.
Use a command similar to this, adjusting the name and size as you see fit:
$ qemu-img create -f qcow2 alpine-ppc64le.qcow2 20g Formatting 'alpine-ppc64le.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=21474836480 lazy_refcounts=off refcount_bits=16
Use a command like this to boot from CD-ROM:
$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -cdrom alpine-standard-3.19.1-ppc64le.iso
A great many messages will spew to the console ; you may click the symbol to show these if you’re interested.
Bootup messages (CD-ROM)
After the boot completes, you’ll be prompted to login ; login as root:
Welcome to Alpine Linux 3.19 Kernel 6.6.14-0-lts on an ppc64le (/dev/hvc0) localhost login: root Welcome to Alpine! The Alpine Wiki contains a large amount of how-to guides and general information about administrating Alpine systems. See <https://wiki.alpinelinux.org/>. You can setup the system with the command: setup-alpine You may change this message by editing /etc/motd. localhost:~#
To install Alpine to the disk, just run setup-alpine in the usual way. Note that you will need a working internet connection (and appropriate Alpine mirror) in order for apk to add packages during the installation.
localhost:~# setup-alpine ALPINE LINUX INSTALL ---------------------- Hostname ---------- Enter system hostname (fully qualified form, e.g. 'foo.example.org') [localhost] alpine-ppc64le
Most of the setup is common, so it’s hidden (expand with ).
setup-alpine interactive dialog
After the preliminaries, you’ll be asked to select a disk, which should be sda.
Disk & Install ---------------- Available disks are: sda (21.5 GB QEMU QEMU HARDDISK ) Which disk(s) would you like to use? (or '?' for help or 'none') [none] sda The following disk is selected: sda (21.5 GB QEMU QEMU HARDDISK ) How would you like to use it? ('sys', 'data', 'crypt', 'lvm' or '?' for help) [?] sys WARNING: The following disk(s) will be erased: sda (21.5 GB QEMU QEMU HARDDISK ) WARNING: Erase the above disk(s) and continue? (y/n) [n] y Creating file systems...
At this point, one of two things will happen:
If everything worked well, proceed to Booting from the hard disk below. Otherwise, read on…
On my system, setup-alpine then says:
mkswap: can't open '/dev/sda3': No such file or directory swapon: /dev/sda3: No such file or directory The file /dev/sda4 does not exist and no size was specified. mount: mounting /dev/sda4 on /mnt failed: No such file or directory alpine-ppc64le:~#
After some investigation, I discovered the reason for this – a race condition in mdev – and have documented it in the Appendix: sda partitions disappearing.
A solution: back up the partition table, create a new disk label, then restore the partitions. This will recreate the device nodes, which are needed to complete the installation.
This procedure will recreate the /dev/sda[1-4] device nodes if they disappeared:
alpine-ppc64le:~# sfdisk -d /dev/sda > /tmp/sda.sfdisk alpine-ppc64le:~# echo "label: dos" | sfdisk /dev/sda Checking that no-one is using this disk right now ... OK Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors Disk model: QEMU HARDDISK Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x2bcfab69 Old situation: Device Boot Start End Sectors Size Id Type /dev/sda1 * 2048 18431 16384 8M 41 PPC PReP Boot /dev/sda2 18432 632831 614400 300M 83 Linux /dev/sda3 632832 2496511 1863680 910M 82 Linux swap / Solaris /dev/sda4 2496512 41943039 39446528 18.8G 83 Linux >>> Script header accepted. >>> Done. Created a new DOS (MBR) disklabel with disk identifier 0x7f0b591c. New situation: Disklabel type: dos Disk identifier: 0x7f0b591c The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. alpine-ppc64le:~# sfdisk /dev/sda < /tmp/sda.sfdisk Checking that no-one is using this disk right now ... OK Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors Disk model: QEMU HARDDISK Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x7f0b591c Old situation: >>> Script header accepted. >>> Script header accepted. >>> Script header accepted. >>> Script header accepted. >>> Script header accepted. >>> Created a new DOS (MBR) disklabel with disk identifier 0x2bcfab69. /dev/sda1: Created a new partition 1 of type 'PPC PReP Boot' and of size 8 MiB. /dev/sda2: Created a new partition 2 of type 'Linux' and of size 300 MiB. Partition #2 contains a ext4 signature. /dev/sda3: Created a new partition 3 of type 'Linux swap / Solaris' and of size 910 MiB. /dev/sda4: Created a new partition 4 of type 'Linux' and of size 18.8 GiB. All partitions used. New situation: Disklabel type: dos Disk identifier: 0x2bcfab69 Device Boot Start End Sectors Size Id Type /dev/sda1 * 2048 18431 16384 8M 41 PPC PReP Boot /dev/sda2 18432 632831 614400 300M 83 Linux /dev/sda3 632832 2496511 1863680 910M 82 Linux swap / Solaris /dev/sda4 2496512 41943039 39446528 18.8G 83 Linux The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. alpine-ppc64le:~#
At this point, the partitioning is done, but some of the filesystems may not have been created properly, so this must now be done. mkfs the /boot and / partitions, and mkswap and swapon the swap partition. The PPC PReP Boot partition does not contain a filesystem (it is simply grub’s core.elf file copied directly to it), so do not format it.
You may get warnings that one or more of the filesystems are already formatted. In my tests, despite the format having been done on /boot, there was never any data there.
alpine-ppc64le:~# mkfs.ext4 /dev/sda2 mke2fs 1.47.0 (5-Feb-2023) /dev/sda2 contains a ext4 file system created on Wed Feb 14 06:23:45 2024 Proceed anyway? (y,N) y Discarding device blocks: done Creating filesystem with 307200 1k blocks and 76912 inodes Filesystem UUID: 17458cf3-ab1d-4fc4-9830-46bb7e7ac7d9 Superblock backups stored on blocks: 8193, 24577, 40961, 57345, 73729, 204801, 221185 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done alpine-ppc64le:~# mkfs.ext4 /dev/sda4 mke2fs 1.47.0 (5-Feb-2023) Discarding device blocks: done Creating filesystem with 4668928 4k blocks and 1169168 inodes Filesystem UUID: 2f4b3c15-f6ba-41e7-b8ef-81fa8d660c34 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000 Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done alpine-ppc64le:~# mkswap /dev/sda3 Setting up swapspace version 1, size = 2026831872 bytes UUID=88774688-bb25-42c0-aa7b-1ee0c6288716 alpine-ppc64le:~# swapon /dev/sda3 alpine-ppc64le:~#
If you are building an image template, you might consider omitting the swapon command, so that the image size can be minimized.
Before transferring the system to the disk, it needs to be mounted. Start with /, make a directory for /boot, and mount it, too:
alpine-ppc64le:~# mount /dev/sda4 /mnt alpine-ppc64le:~# mkdir /mnt/boot alpine-ppc64le:~# mount /dev/sda2 /mnt/boot alpine-ppc64le:~#
Now execute setup-disk, pointing it at the mountpoint used above:
alpine-ppc64le:~# SWAP_DEVICES=/dev/sda3 setup-disk /mnt Installing system on /dev/sda4: 100% ████████████████████████████████████████████==> initramfs: creating /boot/initramfs-lts for 6.6.16-0-lts Generating grub configuration file ... Found linux image: /boot/vmlinuz-lts Found initrd image: /boot/initramfs-lts Warning: os-prober will not be executed to detect other bootable partitions. Systems on them will not be added to the GRUB boot configuration. Check GRUB_DISABLE_OS_PROBER documentation entry. done alpine-ppc64le:~#
Specifying SWAP_DEVICES causes an entry for swap to be placed in /mnt/etc/fstab, so that it can be added at boot.
I was initially confused about the mention of grub, believing that that was done. But, although there is a grub config file now, grub itself is not installed to the hard disk yet, and the system isn’t directly bootable. ( In theory, you could use the CD-ROM to get into grub, then boot the kernel and initrd from the hard drive, but it’s a bit fiddly.)
The final step of the installation is to install the grub bootloader. The first parameter is the path to /boot (which is actually /mnt/boot at this moment) ; the second parameter is the path to the PPC PReP Boot partition:
alpine-ppc64le:~# grub-install --boot-directory=/mnt/boot /dev/sda1 Installing for powerpc-ieee1275 platform. Installation finished. No error reported. alpine-ppc64le:~#
At this point, the system is installed and should be bootable from the hard disk.
Now you could just reboot ; Open Firmware will (by default) try to boot from the hard disk first. But I usually prefer to power down instead, so I can modify the qemu launch parameters slightly:
alpine-ppc64le:~# poweroff [...snip...] * Terminating remaining processes ...reboot: Power down
When relauching, I usually make provisions for an inbound SSH connection:
$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22
Bootup messages (hard drive)
If all goes well, you’ll eventually be rewarded with:
Welcome to Alpine Linux 3.19 Kernel 6.6.16-0-lts on an ppc64le (/dev/hvc0) alpine-ppc64le login:
Notice that the kernel version is newer than what is on the CD-ROM image ; a sure sign that it booted from the hard disk. (And try to ignore the error of “an ppc64le” – or, better yet, change it!)
[ To be tried, eventually… ]
The boot sequence is governed by nvram variables, particularly boot-device and auto-boot?. If you don’t specify a pflash device or an nvram variable override on the command line, boot-device will be unset, and auto-boot? will be true. In this configuration, devices are tried, seemingly in this order:
If none are bootable, you’ll be dumped into the Open Firmware shell, where you could attempt to boot manually.
As part of the grub-install process, the grub bootloader image core.elf will be generated. This file is in a format that can be directly executed by Open Firmware. It’s placed into /boot/grub/powerpc-ieee1275/core.elf ; but also rather more conveniently in the file /boot/grub/grub.
The PPC PReP Boot partition (/dev/sda1 in the examples above) is a copy of this core.elf file. There is no filesystem ; the file is just copied directly onto the partition by grub-install.
You can prove that easily enough:
alpine-ppc64le:~# ls -l /boot/grub/grub /boot/grub/powerpc-ieee1275/core.elf -rw-r--r-- 1 root root 86372 Feb 19 03:03 /boot/grub/grub -rw-r--r-- 1 root root 86372 Feb 19 03:03 /boot/grub/powerpc-ieee1275/core.elf alpine-ppc64le:~# dd if=/dev/sda1 of=/tmp/dev.sda1 bs=572 count=151 151+0 records in 151+0 records out 86372 bytes (84.3KB) copied, 0.004337 seconds, 19.0MB/s alpine-ppc64le:~# cmp /boot/grub/grub /tmp/dev.sda1 alpine-ppc64le:~# cmp /boot/grub/powerpc-ieee1275/core.elf /tmp/dev.sda1 alpine-ppc64le:~#
According to the Gentoo Wiki section on Creating the PPC PReP boot partition, the maximum size of this partition is 8 MB. Actually, you need a lot less than that, as the core.elf file is only 84 KB or so.
This partition is used when you boot the hard disk directly, for example:
0 > boot disk:
It is also used by the default boot sequence (ie, the one you get when the boot-device parameter is unset, as it is by default).
Strictly speaking, the PPC PReP Boot partition is not necessary. Open Firmware can read executable images from ext2, ext4, FAT, ISO 9660, and possibly others. (In my tests, ext4 sometimes flaked out, so if you have trouble, you could try ext2.)
Normally, when you run grub-install on this platform, you should pass it the location of your PPC PReP Boot partition, so that it can copy the grub image to it. But what if you forget that parameter?
If you run grub-install without telling it where your PPC PReP Boot partition is, it will still create the various needed files under /boot, but won’t modify your PPC PReP Boot partition, assuming you even have one. Not specifying such a partition is not an error (according to grub-install):
# I don't recommend you do it this way, but: alpine-ppc64le:~# grub-install --boot-directory=/mnt/boot Installing for powerpc-ieee1275 platform. Installation finished. No error reported. alpine-ppc64le:~#
You can see that /dev/sda1 remains untouched:
alpine-ppc64le:~# dd if=/dev/sda1 | hexdump 0000000 0000 0000 0000 0000 0000 0000 0000 0000 * 16384+0 records in 16384+0 records out 8388608 bytes (8.0MB) copied, 0.275080 seconds, 29.1MB/s 0800000 alpine-ppc64le:~#
But, the appropriate files were generated under /mnt/boot (/mnt because the system has just completed the initial install and hasn’t rebooted yet):
alpine-ppc64le:~# ls -l /mnt/boot/grub/grub /mnt/boot/grub/powerpc-ieee1275/core.elf -rw-r--r-- 1 root root 86372 Mar 1 08:50 /mnt/boot/grub/grub -rw-r--r-- 1 root root 86372 Mar 1 08:50 /mnt/boot/grub/powerpc-ieee1275/core.elf alpine-ppc64le:~#
If at this point you reboot, the system will boot from the hard drive as expected. That is because grub-install modified the boot-device nvram variable.
alpine-ppc64le:~# reboot [...snip...] Populating /vdevice/v-scsi@71000003 SCSI: Looking for devices 8000000000000000 DISK : "QEMU QEMU HARDDISK 2.5+" 8200000000000000 CD-ROM : "QEMU QEMU CD-ROM 2.5+" [...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf ... slash more... more... got it Successfully loaded Welcome to GRUB!
Notice the boot path: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf. Generally the syntax is:
device:partitionNumber,pathToFile
The device path is actually given in some of the boot messages. The partition numbering is the same as fdisk uses. Open Firmware uses backslashes as a path separator.
Rebooting to Open Firmware, it’s possible to see where this is defined:
alpine-ppc64le:~# reboot [...snip...] SLOF ********************************************************************** QEMU Starting Build Date = Sep 18 2023 18:57:48 FW Version = git-3a259df2449fc4a4 Press "s" to enter Open Firmware. s [...snip...] Type 'boot' and press return to continue booting the system. Type 'reset-all' and press return to reboot the system. Ready! 0 > printenv boot-device Current: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf Default: ok 0 >
As the instructions say, you could just type boot:
0 > boot Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf ... slash more... more... got it Successfully loaded Welcome to GRUB!
If you wanted to shorten the boot-device, you could use a devalias in place of the full device name:
0 > devalias keyboard : /pci@800000020000000/usb-xhci@1/usb-keyboard@1 usb0 : /pci@800000020000000/usb-xhci@1 screen : /pci@800000020000000/vga@0 scsi : /vdevice/v-scsi@71000003 cdrom : /vdevice/v-scsi@71000003/disk@8200000000000000 disk : /vdevice/v-scsi@71000003/disk@8000000000000000 net : /vdevice/l-lan@71000002 nvram : /vdevice/nvram@71000001 hvterm : /vdevice/vty@71000000 ok 0 > boot disk:2,\grub\powerpc-ieee1275\core.elf Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf ... slash more... more... got it Successfully loaded Welcome to GRUB!
Remembering that there is also /boot/grub/grub, you could use an even shorter name to boot:
0 > boot disk:2,\grub\grub Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\grub ... slash more... got it Successfully loaded Welcome to GRUB!
However, when you power off the system, and relaunch it, it will no longer automatically boot:
alpine-ppc64le:~# poweroff [...snip...] Requesting system poweroff reboot: Power down$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22[...snip...] SLOF ********************************************************************** QEMU Starting Build Date = Sep 18 2023 18:57:48 FW Version = git-3a259df2449fc4a4 Press "s" to enter Open Firmware. [...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000 ... E3403: Bad executable: E3406: Client application returned an error. Trying to load: from: /vdevice/v-scsi@71000003/disk@8200000000000000 ... No medium ! E3405: No such device [...snip...] Type 'boot' and press return to continue booting the system. Type 'reset-all' and press return to reboot the system. Ready! 0 >
The automatic boot failed, because there was no boot-device defined, and the PPC PReP Boot partition is just a bunch of zeros. You can still boot manually, though:
0 > boot disk:2,\grub\grub Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\grub ... slash more... got it Successfully loaded Welcome to GRUB!
There are three ways to restore automatic booting:
If by chance or choice you should wind up with a blank PPC PReP Boot partition, fret not: it can be (re)populated.
First, you should check to make sure you have the right partition:
alpine-ppc64le:~# fdisk -l /dev/sda Disk /dev/sda: 20 GB, 21474836480 bytes, 41943040 sectors 20480 cylinders, 64 heads, 32 sectors/track Units: sectors of 1 * 512 = 512 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/sda1 * 1,0,1 8,63,32 2048 18431 16384 8192K 41 PPC PReP Boot /dev/sda2 9,0,1 308,63,32 18432 632831 614400 300M 83 Linux /dev/sda3 309,0,1 1023,63,32 632832 4591615 3958784 1933M 82 Linux swap /dev/sda4 1023,63,32 1023,63,32 4591616 41943039 37351424 17.8G 83 Linux alpine-ppc64le:~#
If you’re able to manually boot the target system (eg, using a boot command as above), you could just run grub-install with the parameters it should’ve had in the first place, for example:
alpine-ppc64le:~# grub-install --boot-directory=/boot /dev/sda1 Installing for powerpc-ieee1275 platform. Installation finished. No error reported. alpine-ppc64le:~# reboot [...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000 ... Successfully loaded Welcome to GRUB!
Note that now the boot-directory is simply /boot (not /mnt/boot), as you are in the target system.
Another way to do it, a bit more directly perhaps, would be to just copy the core.elf file directly onto the partition:
alpine-ppc64le:~# dd if=/boot/grub/powerpc-ieee1275/core.elf of=/dev/sda1 168+1 records in 168+1 records out 86372 bytes (84.3KB) copied, 0.006051 seconds, 13.6MB/s alpine-ppc64le:~# reboot [...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000 ... Successfully loaded Welcome to GRUB!
But what if you had never run grub-install? Well, that would be somewhat problematic, because then there will be no core.elf file on the disk to boot from. Fortunately you could use the grub bootloader on the CD-ROM to boot from the hard disk:
$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -cdrom alpine-standard-3.19.1-ppc64le.iso
As soon as you see the message:
The highlighted entry will be executed automatically in 3s.
press e to edit the grub commands:
GNU GRUB version 2.06 +----------------------------------------------------------------------------+ |*Linux lts | | | | | | | | | | | | | | | | | | | | | | | +----------------------------------------------------------------------------+ Use the ^ and v keys to select which entry is highlighted. Press enter to boot the selected OS, `e' to edit the commands before booting or `c' for a command-line. The highlighted entry will be executed automatically in 0s.e
Now you need to add the root device, that is, where the /boot partition is on the hard disk. You also need to add the ext4 module, and the ro and root kernel parameters:
GNU GRUB version 2.06 +----------------------------------------------------------------------------+ |setparams 'Linux lts' | |set root=(ieee1275/disk,2) | |linux /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage,ibm\| |vscsi,ext4 quiet console=hvc0 ro root=/dev/sda4 | |initrd /boot/initramfs-lts | | | | | | | | | | | | | | | +----------------------------------------------------------------------------+ Minimum Emacs-like screen editing is supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a command-line or ESC to discard edits and return to the GRUB menu.
When finished, press Control-X or F10 to boot. Once booted, login and run grub-install as shown below:
^X Booting a command list OF stdout device is: /vdevice/vty@71000000 Preparing to boot Linux version 6.6.18-0-lts (buildozer@build-3-19-ppc64le) (gcc (Alpine 13.2.1_git20231014) 13.2.1 20231014, GNU ld (GNU Binutils) 2.41) #1-Alpine SMP Mon, 26 Feb 2024 10:23:06 +0000 Detected machine type: 0000000000000101 command line: BOOT_IMAGE=/boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage,ibmvscsi,ext4 quiet console=hvc0 ro root=/dev/sda4 [...snip...] alpine-ppc64le:~# grub-install --boot-directory=/boot /dev/sda1 Installing for powerpc-ieee1275 platform. Installation finished. No error reported. alpine-ppc64le:~# reboot
This is fairly straightforward. Just add a prom-env parameter to your qemu-system-ppc64 command:
$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22 \ -prom-env "boot-device=disk:2,\grub\grub"[...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\grub ... slash more... got it Successfully loaded Welcome to GRUB!
Note that the string has to be quoted (or the backslashes escaped), otherwise those \g would get turned into just g.
Probably on many real PPC64 machines, there would be an actual bit of flash memory, and so nvram variables would be persisted between boots. It’s fairly easy to create one, too. If you create one badly, QEMU will helpfully tell you how big it can be:
qemu-system-ppc64: spapr-nvram must be between 8192 and 1048576 bytes in size
1 MB isn’t really much space nowadays, so I opted for that. The file is essentially treated as a disk, so you can use it ‘raw’, or in something like qcow2 format. The main advantage to using qcow2 is that you can be slightly lazier about the command syntax, to wit:
$ qemu-img create -f qcow2 alpine-ppc64le.pflash 1m Formatting 'alpine-ppc64le.pflash', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16 $ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22 \ -pflash alpine-ppc64le.pflash
If all went well, the system will boot up into Open Firmware. Press s during the boot to access the shell, then enter an appropriate setenv command to set the boot-device variable:
[...snip...] SLOF ********************************************************************** QEMU Starting Build Date = Sep 18 2023 18:57:48 FW Version = git-3a259df2449fc4a4 Press "s" to enter Open Firmware. s [...snip...] Type 'boot' and press return to continue booting the system. Type 'reset-all' and press return to reboot the system. Ready! 0 > setenv boot-device disk:2,\grub\powerpc-ieee1275\core.elf ok 0 >
At this point, you could enter boot ; but I prefer to quit the emulator and relaunch to make sure the variable is persistent. Press Control-A, then c to get to the QEMU console, then q to quit.
0 > ^A cQEMU 8.2.1 monitor - type 'help' for more information (qemu) q
Then relaunch QEMU with the exact same command as before, and it should boot:
$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22 \ -pflash alpine-ppc64le.pflash[...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf ... slash more... more... got it Successfully loaded Welcome to GRUB!
If you prefer a raw pflash image, you can do that. Notice the slightly different syntax required.
$ qemu-img create -f raw alpine-ppc64le.pflash 1m Formatting 'alpine-ppc64le.pflash', fmt=raw size=1048576 $ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22 \ -drive if=pflash,file=alpine-ppc64le.pflash,format=raw[...snip...] SLOF ********************************************************************** QEMU Starting Build Date = Sep 18 2023 18:57:48 FW Version = git-3a259df2449fc4a4 Press "s" to enter Open Firmware. s [...snip...] Type 'boot' and press return to continue booting the system. Type 'reset-all' and press return to reboot the system. Ready! 0 > setenv boot-device disk:2,\grub\powerpc-ieee1275\core.elf ok 0 > ^A cQEMU 8.2.1 monitor - type 'help' for more information (qemu) q$ qemu-system-ppc64 -m 1024 -nographic \ -hda alpine-ppc64le.qcow2 \ -nic user,hostfwd=tcp:127.0.0.1:22226-:22 \ -drive if=pflash,file=alpine-ppc64le.pflash,format=raw[...snip...] Trying to load: from: /vdevice/v-scsi@71000003/disk@8000000000000000:2,\grub\powerpc-ieee1275\core.elf ... slash more... more... got it Successfully loaded Welcome to GRUB!
One nice thing about the raw format is you can easily look into the flash device to see what’s inside:
$ strings alpine-ppc64le.pflash | grep boot-device boot-device=disk:2,\grub\powerpc-ieee1275\core.elf
At first I assumed the CD-ROM boot worked much like the hard disk boot, and was laid out something like a hybrid ISO+MBR. But the partition table says otherwise:
$ fdisk alpine-standard-3.19.1-ppc64le.iso Disk: alpine-standard-3.19.1-ppc64le.iso geometry: 1002/4/63 [252712 sectors] Signature: 0xAA55 Starting Ending #: id cyl hd sec - cyl hd sec [ start - size] ------------------------------------------------------------------------ *1: CD 0 0 2 - 123 25 8 [ 1 - 252711] <Unknown ID> 2: 00 0 0 0 - 0 0 0 [ 0 - 0] unused 3: 00 0 0 0 - 0 0 0 [ 0 - 0] unused 4: 00 0 0 0 - 0 0 0 [ 0 - 0] unused
(The partition type is 0xCD – that’s cute…)
Instead, a file ppc/bootinfo.txt seems to be the way this is controlled:
$ 7z e -so alpine-standard-3.19.1-ppc64le.iso ppc/bootinfo.txt | grep boot-script <boot-script>boot &device;:\boot\grub\powerpc.elf</boot-script>
As expected, that file is there:
$ 7z l alpine-standard-3.19.1-ppc64le.iso boot/grub/powerpc.elf | egrep '(^ |powerpc)' Date Time Attr Size Compressed Name 2024-01-26 09:54:11 ..... 89080 89080 boot/grub/powerpc.elf
There could well be some other nuances to a ‘proper’ CD-ROM boot, as I see some empty directories (ppc/chrp) and zero-byte files (mach_kernel), which suggest that it might take more than just ppc/bootinfo.txt, at least on some systems.
[ To be tried, eventually… ]
During the installation, I saw complaints about missing partitions (eg mkswap: can't open '/dev/sda3': No such file or directory) . This is rather strange, as the partitions are defined on the disk…
alpine-ppc64le:~# fdisk -l /dev/sda Disk /dev/sda: 20 GB, 21474836480 bytes, 41943040 sectors 20480 cylinders, 64 heads, 32 sectors/track Units: sectors of 1 * 512 = 512 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/sda1 * 1,0,1 8,63,32 2048 18431 16384 8192K 41 PPC PReP Boot /dev/sda2 9,0,1 308,63,32 18432 632831 614400 300M 83 Linux /dev/sda3 309,0,1 1023,63,32 632832 4591615 3958784 1933M 82 Linux swap /dev/sda4 1023,63,32 1023,63,32 4591616 41943039 37351424 17.8G 83 Linux alpine-ppc64le:~#
…but the partition device nodes are missing:
alpine-ppc64le:~# ls -l /dev/sda* brw-rw---- 1 root disk 8, 0 Feb 14 06:23 /dev/sda alpine-ppc64le:~#
You can run partprobe to make them reappear temporarily ; but after a few seconds, they are gone again:
alpine-ppc64le:~# partprobe /dev/sda ; ls -l /dev/sda* ; sleep 3 ; echo ; ls -l /dev/sda* brw-rw---- 1 root disk 8, 0 Feb 14 06:23 /dev/sda brw------- 1 root root 8, 1 Feb 14 12:31 /dev/sda1 brw------- 1 root root 8, 2 Feb 14 12:31 /dev/sda2 brw------- 1 root root 8, 3 Feb 14 12:31 /dev/sda3 brw------- 1 root root 8, 4 Feb 14 12:31 /dev/sda4 brw-rw---- 1 root disk 8, 0 Feb 14 06:23 /dev/sda alpine-ppc64le:~#
So this is why the installer is choking: the partition devices are gone by the time it tries to use them!
To troubleshoot what mdev was doing, I created the file /dev/mdev.log before running setup-alpine:
localhost:~# touch /dev/mdev.log localhost:~# setup-alpine [...] Creating file systems... mkswap: can't open '/dev/sda3': No such file or directory swapon: /dev/sda3: No such file or directory The file /dev/sda4 does not exist and no size was specified. mount: mounting /dev/sda4 on /mnt failed: No such file or directory alpine-ppc64le:~# grep sda1 /dev/mdev.log | cut -d\ -f1-6 mdev[1949]: 07:07:46.250267 ACTION:add SEQNUM:1949 SUBSYSTEM:block DEVNAME:sda1 mdev[1949]: mknod sda1 (8,1) 60660 0:6 mdev[1953]: 07:07:50.416952 ACTION:remove SEQNUM:1953 SUBSYSTEM:block DEVNAME:sda1 mdev[1958]: 07:07:50.468030 ACTION:add SEQNUM:1958 SUBSYSTEM:block DEVNAME:sda1 mdev[1958]: mknod sda1 (8,1) 60660 0:6 mdev[1962]: 07:07:51.239840 ACTION:remove SEQNUM:1962 SUBSYSTEM:block DEVNAME:sda1 mdev[1967]: 07:07:51.468277 ACTION:add SEQNUM:1967 SUBSYSTEM:block DEVNAME:sda1 mdev[1967]: mknod sda1 (8,1) 60660 0:6 mdev[1953]: unlink: sda1 mdev[1962]: unlink: sda1 alpine-ppc64le:~#
According to the ACTION events, the sequence should be:
The result would be that /dev/sda1 exists. But the actual sequence of events is:
It seems that the remove actions are all happening at the end, with the end result that the device nodes are gone.
Armed with this information, I found a Stack Overflow question, mdev racing when creating and deleting device node. And the problem described seems to be the exact one I’m facing. But why is the partition information changing so many times?
Perhaps unsurprisingly, creating a setup program for a panopoly of architectures, all of which have different boot methods and requirements, is non-trivial. It’s likely that setup-disk was created long before ppc64le support was added to Alpine, as there are several special cases for this architecture. In any event, let us see how setup-disk works on this platform.
I replaced /sbin/sfdisk with a small wrapper to see what input was being passed to it, and which arguments. Here is a run of setup-disk with this wrapper in place:
alpine-ppc64le:~# cat /sbin/sfdisk #!/bin/zsh if [ "$1" = "-d" ]; then /sbin/sfdisk.real $* else echo "+++++ sfdisk $*" >&2 tee >(/sbin/sfdisk.real $*) >&2 sleep 3 ls -l /dev/sda* echo "----- sfdisk $*" >&2 fi alpine-ppc64le:~# setup-disk -m sys /dev/sda WARNING: The following disk(s) will be erased: sda (21.5 GB QEMU QEMU HARDDISK ) WARNING: Erase the above disk(s) and continue? (y/n) [n] y +++++ sfdisk --quiet /dev/sda label: dos brw-rw---- 1 root disk 8, 0 Mar 16 08:33 /dev/sda ----- sfdisk --quiet /dev/sda +++++ sfdisk --quiet --wipe-partitions always --label dos /dev/sda ,8M,41 ,300M,83,* ,910M,82 ,,83 brw-rw---- 1 root disk 8, 0 Mar 16 08:33 /dev/sda brw-rw---- 1 root disk 8, 1 Mar 16 08:33 /dev/sda1 brw-rw---- 1 root disk 8, 2 Mar 16 08:33 /dev/sda2 brw-rw---- 1 root disk 8, 3 Mar 16 08:33 /dev/sda3 brw-rw---- 1 root disk 8, 4 Mar 16 08:33 /dev/sda4 ----- sfdisk --quiet --wipe-partitions always --label dos /dev/sda +++++ sfdisk --quiet /dev/sda -N1 ,,,* brw-rw---- 1 root disk 8, 0 Mar 16 08:33 /dev/sda ----- sfdisk --quiet /dev/sda -N1 +++++ sfdisk --quiet /dev/sda -N2 ,,,- brw-rw---- 1 root disk 8, 0 Mar 16 08:33 /dev/sda ----- sfdisk --quiet /dev/sda -N2 Creating file systems... The file /dev/sda2 does not exist and no size was specified. mkswap: can't open '/dev/sda3': No such file or directory swapon: /dev/sda3: No such file or directory The file /dev/sda4 does not exist and no size was specified. mount: mounting /dev/sda4 on /mnt failed: No such file or directory alpine-ppc64le:~#
It seems sfdisk gets called to modify the disk four times:
Why does setup-disk initially partition the disk with the boot flag on sda2, then later move it to sda1?
Feel free to contact me with any questions, comments, or feedback.