Skip to content

Commit

Permalink
initcpio: Move firmware unpacking to the initramfs
Browse files Browse the repository at this point in the history
This solves the flakines due to udev getting uevents for devices before
the firmware is updated, and gets rid of the dodgy systemd units
involved. Now the initramfs is in charge of unpacking firmware twice:
once for itself, once to update the rootfs firmware (if required).

This is all fast enough that there isn't any significant impact on boot
time.

Signed-off-by: Hector Martin <marcan@marcan.st>
  • Loading branch information
marcan committed Sep 18, 2022
1 parent cd95a69 commit 473ae74
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 8 deletions.
9 changes: 4 additions & 5 deletions Makefile
@@ -1,9 +1,8 @@
PREFIX=/usr/local

SCRIPTS=update-vendor-firmware update-grub first-boot update-m1n1
UNITS=first-boot.service update-vendor-firmware.service systemd-udev-trigger-early.service
UNITS=first-boot.service
MULTI_USER_WANTS=first-boot.service
SYSINIT_WANTS=update-vendor-firmware.service systemd-udev-trigger-early.service

install:
install -d $(DESTDIR)$(PREFIX)/bin/
Expand All @@ -13,10 +12,10 @@ install:
install -m0644 -t $(DESTDIR)$(PREFIX)/lib/systemd/system $(addprefix systemd/,$(UNITS))
ln -sf $(addprefix $(PREFIX)/lib/systemd/system/,$(MULTI_USER_WANTS)) \
$(DESTDIR)$(PREFIX)/lib/systemd/system/multi-user.target.wants/
ln -sf $(addprefix $(PREFIX)/lib/systemd/system/,$(SYSINIT_WANTS)) \
$(DESTDIR)$(PREFIX)/lib/systemd/system/sysinit.target.wants/
install -dD $(DESTDIR)$(PREFIX)/lib/initcpio/install
install -m0644 -t $(DESTDIR)$(PREFIX)/lib/initcpio/install initcpio/install/asahi
install -dD $(DESTDIR)$(PREFIX)/lib/initcpio/hooks
install -m0644 -t $(DESTDIR)$(PREFIX)/lib/initcpio/hooks initcpio/hooks/asahi
install -dD $(DESTDIR)$(PREFIX)/share/libalpm/hooks
install -m0644 -t $(DESTDIR)$(PREFIX)/share/libalpm/hooks libalpm/hooks/95-m1n1-install.hook
install -dD $(DESTDIR)/etc
Expand All @@ -28,8 +27,8 @@ uninstall:
rm -f $(addprefix $(DESTDIR)$(PREFIX)/bin/,$(SCRIPTS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)/lib/systemd/system/,$(UNITS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)/lib/systemd/system/multi-user.target.wants/,$(MULTI_USER_WANTS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)/lib/systemd/system/sysinit.target.wants/,$(SYSINIT_WANTS))
rm -f $(DESTDIR)$(PREFIX)/lib/initcpio/install/asahi
rm -f $(DESTDIR)$(PREFIX)/lib/initcpio/hooks/asahi
rm -f $(DESTDIR)$(PREFIX)/share/libalpm/hooks/95-m1n1-install.hook
rm -rf $(DESTDIR)$(PREFIX)/share/asahi-scripts

Expand Down
6 changes: 4 additions & 2 deletions functions.sh
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: MIT

# NOTE: These functions are used in the initramfs, so they must be ash/busybox compatible!

info() {
echo "$@" 1>&2
}
Expand All @@ -17,7 +19,7 @@ mount_sys_esp() {
umount "$mountpoint"
done

esp_uuid="$(cat /proc/device-tree/chosen/asahi,efi-system-partition 2>/dev/null | tr -d '\0')"
esp_uuid="$(cat /proc/device-tree/chosen/asahi,efi-system-partition 2>/dev/null | sed 's/\x00//')"
if [ -z "$esp_uuid" ]; then
if [ -e "/boot/efi/m1n1" ]; then
bootmnt="/boot/efi"
Expand Down Expand Up @@ -52,7 +54,7 @@ mount_boot_esp() {
elif [ -e "/boot/efi/boot" ]; then
mount --bind "/boot" "$mountpoint"
else
esp_uuid="$(cat /proc/device-tree/chosen/asahi,efi-system-partition | tr -d '\0')"
esp_uuid="$(cat /proc/device-tree/chosen/asahi,efi-system-partition | sed 's/\x00//')"

if [ -z "$esp_uuid" ]; then
echo "Boot ESP not found and cannot determine ESP PARTUUID."
Expand Down
33 changes: 33 additions & 0 deletions initcpio/hooks/asahi
@@ -0,0 +1,33 @@
#!/usr/bin/ash

run_earlyhook() {
if [ ! -e /proc/device-tree/chosen/asahi,efi-system-partition ]; then
msg ":: Asahi: Missing asahi,efi-system-partition variable, firmware will not be loaded!"
return 1
fi

msg ":: Asahi: Triggering early load of NVMe modules..."
modprobe apple-mailbox
modprobe nvme-apple

for i in $(seq 0 50); do
[ -e /sys/bus/platform/drivers/nvme-apple/*.nvme/nvme/nvme*/nvme*n1/ ] && break
sleep 0.1
done

if [ ! -e /sys/bus/platform/drivers/nvme-apple/*.nvme/nvme/nvme*/nvme*n1/ ]; then
err "Timed out waiting for NVMe device"
return 1
fi

# If the above exists, hopefully the /dev device exists and this will work
msg ":: Asahi: Unpacking vendor firmware into initramfs..."
mkdir -p /lib/firmware
ash /usr/bin/update-vendor-firmware
}

run_latehook() {
msg ":: Asahi: Updating vendor firmware in root filesystem..."
mkdir -p /new_root/lib/firmware
TARGET_ROOT=/new_root ash /usr/bin/update-vendor-firmware
}
9 changes: 8 additions & 1 deletion initcpio/install/asahi
Expand Up @@ -7,7 +7,7 @@ build() {
add_module apple-mailbox?

# For NVMe
add_module nvme_apple?
add_module nvme-apple?

# For USB and HID
add_module pinctrl-apple-gpio?
Expand All @@ -28,6 +28,13 @@ build() {

# For MTP HID
map add_module apple-dockchannel? dockchannel-hid? apple-rtkit-helper?

# asahi-scripts dependencies
add_full_dir /usr/share/asahi-scripts
add_binary /usr/bin/update-vendor-firmware

# Firmware update script
add_runscript
}

help() {
Expand Down
2 changes: 2 additions & 0 deletions update-vendor-firmware
@@ -1,6 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: MIT

# NOTE: This script runs in the initramfs, so it must be ash/busybox compatible!

set -e

[ -e /etc/default/update-vendor-firmware ] && source /etc/default/update-vendor-firmware
Expand Down

0 comments on commit 473ae74

Please sign in to comment.