Alpine Linux (ppc64le) in QEMU

Table of contents:

Preparation

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.

Using qemu-system-ppc64

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

Creating a virtual hard disk

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

Booting from the virtual CD-ROM

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)
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-cfpc=workaround
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-sbbc=workaround
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-ibs=workaround
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-ccf-assist=on


SLOF **********************************************************************
QEMU Starting
 Build Date = Sep 18 2023 18:57:48
 FW Version = git-3a259df2449fc4a4
 Press "s" to enter Open Firmware.

Populating /vdevice methods
Populating /vdevice/vty@71000000
Populating /vdevice/nvram@71000001
Populating /vdevice/l-lan@71000002
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+"
Populating /pci@800000020000000
                     00 0000 (D) : 1234 1111    qemu vga
                     00 0800 (D) : 1033 0194    serial bus [ usb-xhci ]
No NVRAM common partition, re-initializing...
Installing QEMU fb



Scanning USB
  XHCI: Initializing
    USB Keyboard
    USB mouse
Using default console: /vdevice/vty@71000000

  Welcome to Open Firmware

  Copyright (c) 2004, 2017 IBM Corporation All rights reserved.
  This program and the accompanying materials are made available
  under the terms of the BSD License available at
  http://www.opensource.org/licenses/bsd-license.php


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 ...   Successfully loaded
Welcome to GRUB!

error: unrecognized number.

                             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.
  Booting `Linux lts'

OF stdout device is: /vdevice/vty@71000000
Preparing to boot Linux version 6.6.14-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 Fri, 26 Jan 2024 11:08:07 +0000
Detected machine type: 0000000000000101
command line: BOOT_IMAGE=/boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage,ibmvscsi quiet console=hvc0
Max number of cores passed to firmware: 2048 (NR_CPUS = 2048)
Calling ibm,client-architecture-support... done
memory layout at init:
  memory_limit : 0000000000000000 (16 MB aligned)
  alloc_bottom : 0000000005630000
  alloc_top    : 0000000030000000
  alloc_top_hi : 0000000040000000
  rmo_top      : 0000000030000000
  ram_top      : 0000000040000000
found display   : /pci@800000020000000/vga@0, opening... done
instantiating rtas at 0x000000002fff0000... done
prom_hold_cpus: skipped
copying OF device tree...
Building dt strings...
Building dt structure...
Device tree strings 0x0000000005640000 -> 0x0000000005640c0a
Device tree struct  0x0000000005650000 -> 0x0000000005660000
Quiescing Open Firmware ...
Booting Linux via __start() @ 0x0000000002000000 ...
Linux ppc64le
#1-Alpine SMP Fr

   OpenRC 0.52.1 is starting up Linux 6.6.14-0-lts (ppc64le)

 * /proc is already mounted
 * Mounting /run ... [ ok ]
 * /run/openrc: creating directory
 * /run/lock: creating directory
 * /run/lock: correcting owner
 * Caching service dependencies ... [ ok ]
 * Remounting devtmpfs on /dev ... [ ok ]
 * Mounting /dev/mqueue ... [ ok ]
 * Mounting modloop  ... * Verifying modloop
 [ ok ]
 * Mounting security filesystem ... [ ok ]
 * Mounting debug filesystem ... [ ok ]
 * Mounting persistent storage (pstore) filesystem ... [ ok ]
 * Starting busybox mdev ... [ ok ]
 * Scanning hardware for mdev ... [ ok ]
 * Loading hardware drivers ... [ ok ]
 * Setting the local clock based on last shutdown time ... [ ok ]
 * Loading modules ... [ ok ]
 * Checking local filesystems  ... [ ok ]
 * Remounting filesystems ... [ ok ]
 * Mounting local filesystems ... [ ok ]
 * Configuring kernel parameters ... [ ok ]
 * Migrating /var/lock to /run/lock ... [ ok ]
 * Creating user login records ... [ ok ]
 * Cleaning /tmp directory ... [ ok ]
 * Setting hostname ... [ ok ]
 * Starting busybox syslog ... [ ok ]
 * Starting firstboot ... [ ok ]

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:~# 

setup-alpine

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
 Interface
-----------
Available interfaces are: eth0.
Enter '?' for help on bridges, bonding and vlans.
Which one do you want to initialize? (or '?' or 'done') [eth0] <enter>
Ip address for eth0? (or 'dhcp', 'none', '?') [dhcp] <enter>
Do you want to do any manual network configuration? (y/n) [n] <enter>
udhcpc: started, v1.36.1
udhcpc: broadcasting discover
udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400

 Root Password
---------------
Changing password for root
New password: 
Bad password: too weak
Retype password: 
passwd: password for root changed by root

 Timezone
----------
Africa/            Egypt              Iran               Poland
America/           Eire               Israel             Portugal
Antarctica/        Etc/               Jamaica            ROC
Arctic/            Europe/            Japan              ROK
Asia/              Factory            Kwajalein          Singapore
Atlantic/          GB                 Libya              Turkey
Australia/         GB-Eire            MET                UCT
Brazil/            GMT                MST                US/
CET                GMT+0              MST7MDT            UTC
CST6CDT            GMT-0              Mexico/            Universal
Canada/            GMT0               NZ                 W-SU
Chile/             Greenwich          NZ-CHAT            WET
Cuba               HST                Navajo             Zulu
EET                Hongkong           PRC                leap-seconds.list
EST                Iceland            PST8PDT            posixrules
EST5EDT            Indian/            Pacific/           right/

Which timezone are you in? [UTC] <enter>

 * Seeding random number generator ...
 * Saving 256 bits of creditable seed for next boot
 [ ok ]
 * Starting busybox acpid ...
 [ ok ]
 * Starting busybox crond ...
 [ ok ]

 Proxy
-------
HTTP/FTP proxy URL? (e.g. 'http://proxy:8080', or 'none') [none] <enter>

 Network Time Protocol
-----------------------
Which NTP client to run? ('busybox', 'openntpd', 'chrony' or 'none') [chrony] <enter>
 * service chronyd added to runlevel default
 * Starting chronyd ...
 [ ok ]

 APK Mirror
------------
 (f)    Find and use fastest mirror
 (s)    Show mirrorlist
 (r)    Use random mirror
 (e)    Edit /etc/apk/repositories with text editor
 (c)    Community repo enable
 (skip) Skip setting up apk repositories

Enter mirror number or URL: [1] <enter>

Added mirror dl-cdn.alpinelinux.org
Updating repository indexes... done.

 User
------
Setup a user? (enter a lower-case loginname, or 'no') [no] <enter>
Which ssh server? ('openssh', 'dropbear' or 'none') [openssh] <enter>
Allow root ssh login? ('?' for help) [prohibit-password] <enter>
Enter ssh key or URL for root (or 'none') [none] <enter>
 * service sshd added to runlevel default
 * Caching service dependencies ...
 [ ok ]
ssh-keygen: generating new host keys: RSA ECDSA ED25519
 * Starting sshd ...
 [ ok ]

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:

  1. Everything will work perfectly, and the system will be installed to the disk ; or
  2. The installation will bomb with a series of errors. ( This has been my experience.)

If everything worked well, proceed to Booting from the hard disk below. Otherwise, read on…

What to do if setup-alpine fails

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.

Repartitioning the drive

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:~# 

Formatting the filesystems

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.

setup-disk

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.)

grub-install

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.

Booting 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)
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-cfpc=workaround
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-sbbc=workaround
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-ibs=workaround
qemu-system-ppc64: warning: TCG doesn't support requested feature, cap-ccf-assist=on


SLOF **********************************************************************
QEMU Starting
 Build Date = Sep 18 2023 18:57:48
 FW Version = git-3a259df2449fc4a4
 Press "s" to enter Open Firmware.

Populating /vdevice methods
Populating /vdevice/vty@71000000
Populating /vdevice/nvram@71000001
Populating /vdevice/l-lan@71000002
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+"
Populating /pci@800000020000000
                     00 0000 (D) : 1234 1111    qemu vga
                     00 0800 (D) : 1033 0194    serial bus [ usb-xhci ]
No NVRAM common partition, re-initializing...
Installing QEMU fb



Scanning USB
  XHCI: Initializing
    USB Keyboard
    USB mouse
Using default console: /vdevice/vty@71000000

  Welcome to Open Firmware

  Copyright (c) 2004, 2017 IBM Corporation All rights reserved.
  This program and the accompanying materials are made available
  under the terms of the BSD License available at
  http://www.opensource.org/licenses/bsd-license.php


Trying to load:  from: /vdevice/v-scsi@71000003/disk@8000000000000000 ...   Successfully loaded
Welcome to GRUB!

error: no suitable video mode found.

                             GNU GRUB  version 2.06

 +----------------------------------------------------------------------------+
 |*Alpine Linux v3.19, with 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.
  Booting `Alpine Linux v3.19, with Linux lts'

Loading Linux lts ...
Loading initial ramdisk ...
OF stdout device is: /vdevice/vty@71000000
Preparing to boot Linux version 6.6.16-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 Wed, 07 Feb 2024 18:00:38 +0000
Detected machine type: 0000000000000101
command line: BOOT_IMAGE=/vmlinuz-lts root=UUID=2f4b3c15-f6ba-41e7-b8ef-81fa8d660c34 ro modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4
Max number of cores passed to firmware: 2048 (NR_CPUS = 2048)
Calling ibm,client-architecture-support... done
memory layout at init:
  memory_limit : 0000000000000000 (16 MB aligned)
  alloc_bottom : 0000000005430000
  alloc_top    : 0000000030000000
  alloc_top_hi : 0000000040000000
  rmo_top      : 0000000030000000
  ram_top      : 0000000040000000
found display   : /pci@800000020000000/vga@0, opening... done
instantiating rtas at 0x000000002fff0000... done
prom_hold_cpus: skipped
copying OF device tree...
Building dt strings...
Building dt structure...
Device tree strings 0x0000000005440000 -> 0x0000000005440c0a
Device tree struct  0x0000000005450000 -> 0x0000000005460000
Quiescing Open Firmware ...
Booting Linux via __start() @ 0x0000000002000000 ...
Linux ppc64le
#1-Alpine SMP We
   OpenRC 0.52.1 is starting up Linux 6.6.16-0-lts (ppc64le)

 * /proc is already mounted
 * Mounting /run ... [ ok ]
 * /run/openrc: creating directory
 * /run/lock: creating directory
 * /run/lock: correcting owner
 * Caching service dependencies ... [ ok ]
 * Remounting devtmpfs on /dev ... [ ok ]
 * Mounting /dev/mqueue ... [ ok ]
 * Mounting security filesystem ... [ ok ]
 * Mounting debug filesystem ... [ ok ]
 * Mounting persistent storage (pstore) filesystem ... [ ok ]
 * Starting busybox mdev ... [ ok ]
 * Scanning hardware for mdev ... [ ok ]
 * Loading hardware drivers ... [ ok ]
 * Setting the local clock based on last shutdown time ... [ ok ]
 * Loading modules ... [ ok ]
 * Checking local filesystems  .../dev/sda4: clean, 2891/1169168 files, 185448/4668928 blocks
/dev/sda2: clean, 241/76912 files, 93803/307200 blocks
 [ ok ]
 * Remounting root filesystem read/write ... [ ok ]
 * Remounting filesystems ... [ ok ]
 * Mounting local filesystems ... [ ok ]
 * Configuring kernel parameters ... [ ok ]
 * Migrating /var/lock to /run/lock ... [ ok ]
 * Creating user login records ... [ ok ]
 * Setting hostname ... [ ok ]
 * Starting networking ... *   lo ... [ ok ]
 *   eth0 ...udhcpc: started, v1.36.1
udhcpc: broadcasting discover
udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400
 [ ok ]
 * Seeding random number generator ... * Saving 256 bits of creditable seed for next boot
 [ ok ]
 * Starting busybox syslog ... [ ok ]
 * Starting busybox acpid ... [ ok ]
 * Starting chronyd ... [ ok ]
 * Starting busybox crond ... [ ok ]
 * Starting sshd ... [ ok ]

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!)

Using virt-install

[ To be tried, eventually… ]

Appendix: the boot process in more detail

Default boot sequence

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:

  1. Hard disk;
  2. CD-ROM;
  3. Network.

If none are bootable, you’ll be dumped into the Open Firmware shell, where you could attempt to boot manually.

Hard disk boot: the PPC PReP Boot partition

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).

Hard disk boot: booting from a file directly

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.


[...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:

  1. If you have a PPC PReP partition, just copy the core.elf file directly onto it, or re-run grub-install; or
  2. Add an nvram variable to your qemu-system-ppc64 command; or
  3. Add a pflash (nvram) device so that the boot-device variable persists between reboots.

Repopulating the PPC PReP Boot partition

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.

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:


  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

Adding an nvram boot-device variable as a QEMU parameter

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.

Persisting the boot-device variable with pflash (nvram)

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.


[...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 > QEMU 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.


[...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 > QEMU 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

CD-ROM boot: ppc/bootinfo.txt

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.

Network boot: DHCP+TFTP

[ To be tried, eventually… ]

Appendix: sda partitions disappearing

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!

mdev troubleshooting

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:

  1. mknod /dev/sda1
  2. unlink /dev/sda1 ; mknod /dev/sda1
  3. unlink /dev/sda1 ; mknod /dev/sda1

The result would be that /dev/sda1 exists. But the actual sequence of events is:

  1. mknod /dev/sda1
  2. mknod /dev/sda1
  3. mknod /dev/sda1
  4. unlink /dev/sda1
  5. unlink /dev/sda1

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?

setup-disk on ppc64le

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:

  1. Create the disklabel (dos).
  2. Partition the disk. Note that the boot partition at this point is /dev/sda2 (/boot), surpringly – not the PPC PReP Boot partition. At this point, everything is still okay.
  3. Set the boot flag on /dev/sda1 ; this means that both sda1 and sda2 are marked bootable. At this point, the device nodes have been deleted, due to the race condition.
  4. Clear the boot flag from /dev/sda2. This does not fix the missing device nodes.

Why does setup-disk initially partition the disk with the boot flag on sda2, then later move it to sda1?

References


Feel free to contact me with any questions, comments, or feedback.