#!/usr/bin/env bash # SPDX-License-Identifier: GPL-2.0-only get_host_vendor() { if grep -aiq 'vendor_id.*amd' /proc/cpuinfo 2>/dev/null; then echo 'amd' elif grep -aiq 'vendor_id.*intel' /proc/cpuinfo 2>/dev/null; then echo 'intel' fi } get_host_ucode() { local vendor="$1" family model stepping family="$(grep -am1 'cpu family' /proc/cpuinfo | sed 's/.*: //')" model="$(grep -am1 'model[[:space:]]*:' /proc/cpuinfo | sed 's/.*: //')" stepping="$(grep -am1 'stepping' /proc/cpuinfo | sed 's/.*: //')" case "$vendor" in amd) # 21 = 15h if (( family >= 21 )); then printf 'amd-ucode/microcode_amd_fam%xh.bin' "$family" else printf 'amd-ucode/microcode_amd.bin' fi ;; intel) printf 'intel-ucode/%02x-%02x-%02x' "$family" "$model" "$stepping" ;; esac } build() { local arch vendor fwpath ucode_file local vendors=(intel amd) local ucode_dest='/kernel/x86/microcode' local -A ucode_dir=([intel]=intel-ucode [amd]=amd-ucode) local -A ucode_img=([intel]=intel-ucode.img [amd]=amd-ucode.img) local -A ucode_bin=([intel]=GenuineIntel.bin [amd]=AuthenticAMD.bin) local -A ucode_glob=([intel]='??-??-??' [amd]='*.bin') local -a ucode_files arch="$(uname -m)" if [[ "$arch" != @(i?86|x86_64) ]]; then warning "architecture '%s' not supported, skipping hook" "$arch" return fi # mkinitcpio_autodetect is assigned in install/autodetect # shellcheck disable=SC2154 if (( mkinitcpio_autodetect )); then vendor="$(get_host_vendor)" ucode_file="$(get_host_ucode "$vendor")" # _d_fwpath is assigned in mkinitcpio # shellcheck disable=SC2154 for fwpath in "${_d_fwpath[@]}"; do if [[ -f "${fwpath}/${ucode_file}" ]]; then quiet "adding microcode file: '%s'" "${fwpath}/${ucode_file}" add_file_early "${fwpath}/${ucode_file}" "${ucode_dest}/${ucode_bin[$vendor]}" 644 return fi done # if no host-specific microcode is found, don't continue and add all microcode return fi for vendor in "${vendors[@]}"; do # find the uncompiled update files and compile them # _d_fwpath is assigned in mkinitcpio # shellcheck disable=SC2154 for fwpath in "${_d_fwpath[@]}"; do if [[ -e "${EARLYROOT}/${ucode_dest}/${ucode_bin[$vendor]}" ]]; then break fi if [[ ! -d "${fwpath}/${ucode_dir[$vendor]}" ]]; then continue fi mapfile -t ucode_files < <(LC_ALL=C.UTF-8 find "${fwpath}/${ucode_dir[$vendor]}" -maxdepth 1 -name "${ucode_glob[$vendor]}") if ! (( ${#ucode_files[@]} )); then continue fi quiet "adding microcode files: '%s'" "${ucode_files[*]}" cat "${ucode_files[@]}" | add_file_early - "${ucode_dest}/${ucode_bin[$vendor]}" 644 break done # as a last resort, find and extract a precompiled image in /boot if [[ ! -e "${EARLYROOT}/${ucode_dest}/${ucode_bin[$vendor]}" && -r "/boot/${ucode_img[$vendor]}" ]]; then quiet "extracting precompiled microcode image: '/boot/%s'" "${ucode_img[$vendor]}" LC_ALL=C.UTF-8 bsdtar -xOf "/boot/${ucode_img[$vendor]}" "${ucode_dest#/}/${ucode_bin[$vendor]}" | \ add_file_early - "${ucode_dest}/${ucode_bin[$vendor]}" 644 fi done } help() { cat <