From fe8c338e6cf1238a390984ba06544833ab8792d3 Mon Sep 17 00:00:00 2001 From: Sharpened Blade Date: Fri, 12 Jul 2024 08:15:36 -0700 Subject: [PATCH] Automate firmware (#558) --- docs/tools/firmware.sh | 204 +++++++++++++++++++------- docs/tools/get-apple-firmware.service | 14 ++ 2 files changed, 168 insertions(+), 50 deletions(-) create mode 100644 docs/tools/get-apple-firmware.service diff --git a/docs/tools/firmware.sh b/docs/tools/firmware.sh index f5c66364..7098ebb5 100755 --- a/docs/tools/firmware.sh +++ b/docs/tools/firmware.sh @@ -1,9 +1,28 @@ #!/usr/bin/env bash -# -# Copyright (C) 2022 Aditya Garg -# Copyright (C) 2022 Orlando Chamberlain + +# Copyright (C) 2024 Aditya Garg +# Copyright (C) 2024 Orlando Chamberlain +# Copyright (C) 2024 Sharpened Blade # # The python script is based upon the original work by The Asahi Linux Contributors. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. rename_firmware () { python3 - "$@" <<'EOF' @@ -336,16 +355,114 @@ EOF set -euo pipefail verbose="" -while getopts "vhxp" option; do +subcmd="" +target_pkg_manager="" +args=() +interactive="true" +while getopts "ivhxp" option; do case $option in + i) interactive="false" ;; v) verbose="-v" ;; - h) echo "usage: $0 [-vhxp] [fw_dir_path output_archive_path]"; exit 0 ;; + h) + cat <<- EOF + usage: $0 [-vhx] subcommand [subcmd args] + + Subcommands: + rename_only /path/to/firmware archive.tar + copy_to_efi + create_archive + create_package apt|rpm|pacman + get_from_efi + get_from_macos + get_from_online + EOF + exit 0 ;; x) set -x;; - p) rename_firmware "${@:2:2}" ${verbose} && exit 0 ;; ?) exit 1 ;; esac done +if [[ "${1-}" == -* ]]; then + subcmd="${2-}" + args=( "${@:3}" ) +else + subcmd="${1-}" + args=( "${@:2}" ) +fi + +if [[ "$subcmd" = "" ]] && [[ "$interactive" = "true" ]]; then + case "$(uname -s)" in + (Darwin) + echo "Detected macOS" + cat <<- EOF + + How do you want to copy the firmware to Linux? + + 1. Copy the firmware to the EFI partition and run the same script on Linux to retrieve it. + 2. Create a tarball of the firmware and extract it to Linux. + 3. Create a Linux specific package which can be installed using a package manager. + + Note: Option 2 and 3 require additional software like python3 and tools specific for your package manager. Requirements will be told as you proceed further. + EOF + read -r choice + case ${choice} in + (1) subcmd="copy_to_efi" ;; + (2) subcmd="create_archive" ;; + (3) subcmd="create_package" + echo -e "\nWhat package manager does your Linux distribution use?\n" + echo "1. apt" + echo "2. dnf" + echo "3. pacman" + read -r target_pkg_manager + case ${target_pkg_manager} in + (1) target_pkg_manager="apt" ;; + (2) target_pkg_manager="rpm" ;; + (3) target_pkg_manager="pacman" ;; + (*) echo -e "\nError: Invalid option!" && exit 1 ;; + esac + ;; + (*) echo -e "\nError: Invalid option!" && exit 1 ;; + esac + ;; + (Linux) + echo "Detected Linux" + cat <<- EOF + + How do you want to copy the firmware to Linux? + + 1. Retrieve the firmware from the EFI partition. + 2. Retrieve the firmware directly from macOS. + 3. Download a macOS Recovery Image from Apple and extract the firmware from there. + + Note: If you are choosing Option 1, then make sure you have run the same script on macOS before and chose Option 1 (Copy the firmware to the EFI partition and run the same script on Linux to retrieve it) there. + EOF + read -r choice + case ${choice} in + (1) + subcmd="get_from_efi" ;; + (2) + subcmd="get_from_macos" ;; + (3) + subcmd="get_from_online" ;; + (*) + echo -e "\nError: Invalid option!" + exit 1 + ;; + esac + ;; + (*) + echo "Error: unsupported platform" + ;; + esac +fi + +if [[ "$subcmd" = "" ]]; then + echo "No subcommand specified" + exit 1 +elif [[ "$subcmd" = "create_package" ]] && [[ "$target_pkg_manager" = "" ]]; then + target_pkg_manager="${args[0]}" +fi + aur_install() { local aur_package=$1 local dir @@ -397,6 +514,11 @@ install_package() { local package=$1 local package_manager package_manager=$(detect_package_manager) + if [[ "$interactive" = "false" ]]; then + echo "$package is missing. Install it then try again" + echo "Exiting" + exit 1 + fi if [[ $package = "linux-apfs-rw" ]] then local apfs_driver_link=https://github.com/linux-apfs/linux-apfs-rw.git @@ -480,6 +602,11 @@ create_firmware_archive() { } python_check () { + if [[ "$interactive" = "false" ]]; then + echo "Xcode command line tools are missing." + echo "Exiting" + exit 1 + fi echo -e "\nChecking for missing dependencies" if [ ! -f "/Library/Developer/CommandLineTools/usr/bin/python3" ] && [ ! -f "/Applications/Xcode.app/Contents/Developer/usr/bin/python3" ] then @@ -708,7 +835,6 @@ nvram_txcap_quirk() { os=$(uname -s) case "$os" in (Darwin) - echo "Detected macOS" ver=$(sw_vers -productVersion) ver_check=$(sw_vers -productVersion | cut -d "." -f 1) identifier=$(system_profiler SPHardwareDataType | grep "Model Identifier" | cut -d ":" -f 2 | xargs) @@ -726,19 +852,8 @@ case "$os" in EOF fi - cat <<- EOF - - How do you want to copy the firmware to Linux? - - 1. Copy the firmware to the EFI partition and run the same script on Linux to retrieve it. - 2. Create a tarball of the firmware and extract it to Linux. - 3. Create a Linux specific package which can be installed using a package manager. - - Note: Option 2 and 3 require additional software like python3 and tools specific for your package manager. Requirements will be told as you proceed further. - EOF - read -r choice - case ${choice} in - (1) + case ${subcmd} in + ("copy_to_efi") echo -e "\nMounting the EFI partition" EFILABEL=$(diskutil info disk0s1 | grep "Volume Name" | cut -d ":" -f 2 | xargs) sudo diskutil mount disk0s1 @@ -751,11 +866,10 @@ case "$os" in echo "Copying this script to EFI" cp "$0" "/Volumes/${EFILABEL}/firmware.sh" 2>/dev/null \ || curl -s https://wiki.t2linux.org/tools/firmware.sh > "/Volumes/${EFILABEL}/firmware.sh" \ - || (echo && cat <<- EOF && read -r + || ( echo && cat <<- EOF && [ "$interactive" = "true" ] && echo "Press enter after you have copied" && read -r Failed to copy script. Please copy the script manually to the EFI partition using Finder Make sure the name of the script is firmware.sh in the EFI partition - Press enter after you have copied" EOF ) sudo diskutil unmount "/Volumes/${EFILABEL}/" @@ -769,7 +883,7 @@ case "$os" in sudo umount /tmp/apple-wifi-efi EOF ;; - (2) + ("create_archive") python_check echo -e "\nCreating a tarball of the firmware" create_firmware_archive /usr/share/firmware "$HOME/Downloads/firmware.tar" @@ -786,21 +900,16 @@ case "$os" in sudo modprobe hci_bcm4377 EOF ;; - (3) - echo -e "\nWhat package manager does your Linux distribution use?\n" - echo "1. apt" - echo "2. dnf" - echo "3. pacman" - read -r package + ("create_package") python_check - case ${package} in - (1) + case ${target_pkg_manager} in + ("apt") create_deb ;; - (2) + ("dnf") create_rpm ;; - (3) + ("pacman") create_arch_pkg ;; (*) @@ -809,6 +918,9 @@ case "$os" in ;; esac ;; + ("rename_only") + rename_firmware "${args[@]}" ${verbose} + ;; (*) echo -e "\nError: Invalid option!" exit 1 @@ -817,7 +929,6 @@ case "$os" in ;; (Linux) - echo "Detected Linux" if [[ ! -e /lib/firmware/brcm ]]; then cat <<- EOF /lib/firmware/brcm does not seem to exist. This script requires that directory to function. @@ -827,19 +938,8 @@ case "$os" in EOF exit 1 fi - cat <<- EOF - - How do you want to copy the firmware to Linux? - - 1. Retrieve the firmware from the EFI partition. - 2. Retrieve the firmware directly from macOS. - 3. Download a macOS Recovery Image from Apple and extract the firmware from there. - - Note: If you are choosing Option 1, then make sure you have run the same script on macOS before and chose Option 1 (Copy the firmware to the EFI partition and run the same script on Linux to retrieve it) there. - EOF - read -r choice - case ${choice} in - (1) + case ${subcmd} in + ("get_from_efi") echo -e "\nRe-mounting the EFI partition" mountpoint=$(mktemp -d) workdir=$(mktemp -d) @@ -860,7 +960,11 @@ case "$os" in done reload_kernel_modules echo -e "\nKeeping a copy of the firmware and the script in the EFI partition shall allow you to set up Wi-Fi again in the future by running this script or the commands told in the macOS step in Linux only, without the macOS step." - read -rp "Do you want to keep a copy? (y/N)" input + if [ "$interactive" = "true" ]; then + read -rp "Do you want to keep a copy? (y/N)" input + else + input="y" + fi if [[ ($input != y) && ($input != Y) ]] then echo -e "\nRemoving the copy from the EFI partition" @@ -878,7 +982,7 @@ case "$os" in sudo rmdir ${verbose} "$mountpoint" echo -e "\nDone!" ;; - (2) + ("get_from_macos") echo -e "\nChecking for missing dependencies" # Load the apfs driver, and install if missing sudo modprobe ${verbose} apfs 2>/dev/null || install_package linux-apfs-rw @@ -925,7 +1029,7 @@ case "$os" in unmount_macos_and_cleanup echo "Done!" ;; - (3) + ("get_from_online") # Detect whether curl and dmg2img are installed echo -e "\nChecking for missing dependencies" curl --version >/dev/null 2>&1 || install_package curl diff --git a/docs/tools/get-apple-firmware.service b/docs/tools/get-apple-firmware.service new file mode 100644 index 00000000..4d198fbe --- /dev/null +++ b/docs/tools/get-apple-firmware.service @@ -0,0 +1,14 @@ +[Unit] +Description=Get Apple WiFi and Bluetooth firmware +ConditionFirstBoot=yes +ConditionPathExists=/lib/firmware/brcm +Wants=first-boot-complete.target +Before=first-boot-complete.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/get-apple-firmware -i get_from_macos + +[Install] +WantedBy=multi-user.target