1#!/bin/ksh 2 3# This file and its contents are supplied under the terms of the 4# Common Development and Distribution License ("CDDL"), version 1.0. 5# You may only use this file in accordance with the terms of version 6# 1.0 of the CDDL. 7# 8# A full copy of the text of the CDDL should have accompanied this 9# source. A copy of the CDDL is also available via the Internet at 10# http://www.illumos.org/license/CDDL. 11 12# Copyright 2022 OmniOS Community Edition (OmniOSce) Association. 13# Copyright 2025 Oxide Computer Company 14 15# A simple update script that checks out the upstream AMD firmware 16# repository, extracts the microcode into separate files within the amd/ 17# directory, generates the required combined equivalence table and updates 18# the pkg(7) manifest. 19 20UPSTREAM=git://git.kernel.org 21UPSTREAM_PATH=/pub/scm/linux/kernel/git/firmware/linux-firmware.git 22 23# These are the GPG keys that AMD use to sign their CPU microcode updates 24# The first key is the current one and the second is one they have used for 25# older CPU families. 26GPGSERVER=keys.gnupg.net 27typeset -a GPGKEYS=( 28 0xFC7C6C505DAFCC14718357CAE4BE5339F328AE73 29 0x916A770823A7B27AADE01565A5E8DBC98C0108B4 30) 31 32function errexit { 33 echo "$@" >&2 34 exit 1 35} 36 37FW=platform/i86pc/ucode/AuthenticAMD 38 39export LC_ALL=C.UTF-8 40 41set -e 42set -o pipefail 43 44mf=../../pkg/manifests/system-microcode-amd.p5m 45[[ -f $mf ]] || errexit "Run from usr/src/data/ucode" 46 47function find_cmd { 48 typeset cmd="$1" 49 typeset var=$(echo $cmd | tr '[:lower:]' '[:upper:]') 50 typeset -n path="$var" 51 path=$(whence -fp "$cmd") 52 if (($? != 0)) || [ ! -x "$path" ]; then 53 errexit "Cannot find executable '$cmd' in PATH" 54 fi 55} 56 57# This script uses a few commands which are not part of illumos and are 58# expected to be available in the path. 59find_cmd git 60find_cmd gpg 61find_cmd pkgfmt 62find_cmd stat 63find_cmd xxd 64# Search for 'ucodeadm'. If you need to use an updated ucodeadm to handle this 65# firmware update, as is occasionally necessary, ensure it occurs earlier in 66# the path than /usr/sbin. 67find_cmd ucodeadm 68 69tmp=$(mktemp -d) 70[[ -n "$tmp" && -d "$tmp" ]] 71mkdir $tmp/out || errexit "Failed to create temporary directory" 72trap 'rm -rf $tmp' EXIT 73 74echo "** Adding AMD GPG signing keys to temporary keyring" 75mkdir -m 0700 $tmp/gnupg 76$GPG --homedir $tmp/gnupg --keyserver $GPGSERVER --receive-keys ${GPGKEYS[@]} 77 78echo "** Cloning $UPSTREAM$UPSTREAM_PATH" 79$GIT clone $UPSTREAM$UPSTREAM_PATH $tmp/ucode 80 81ver=`$GIT -C $tmp/ucode log -n1 --format=%ad --date=format:%Y%m%d amd-ucode` 82echo "** Updating to microcode version $ver" 83 84echo "** Verifying microcode signatures" 85for f in $tmp/ucode/amd-ucode/*.bin; do 86 if [[ ! -f "$f.asc" ]]; then 87 echo "Signature missing for ${f##*/}" 88 exit 1 89 fi 90 $GPG --homedir $tmp/gnupg --trust-model=always --verify $f{.asc,} 91done 92 93# Now that everything is in place and verified, begin modifying the tree. 94 95rm -f amd/*-* 96 97cp $tmp/ucode/LICENSE.amd-ucode amd/THIRDPARTYLICENSE 98echo AMD Processor Microcode Data Files > amd/THIRDPARTYLICENSE.descrip 99 100for f in $tmp/ucode/amd-ucode/*.bin; do 101 bf=${f##*/} 102 bf=${bf#microcode_} 103 bf=${bf%.bin} 104 [[ $bf = amd* ]] || errexit "$f does not look like a firmware file" 105 echo 106 echo "*** Converting $bf" 107 echo 108 mkdir $tmp/out/$bf 109 cp $f $tmp/amd-fw 110 $UCODEADM -l $tmp/amd-fw 111 $UCODEADM -i -R $tmp/out/$bf $tmp/amd-fw 112 rm -f $tmp/amd-fw 113done 114 115# Copy the firmware files into place 116cp $tmp/out/*/*-?? amd/ 117 118# Deal with fallback firmware files (see amd/fallback/README) 119# For some processors AMD ship two microcode versions. One that can only be 120# loaded on systems which are already at a particular firmware level and an 121# older fallback one for systems that running old firmware. They package both 122# of these in the same microcode bundle with nothing to differentiate them 123# apart from their revision number. The older version occurs first in the 124# bundle. On illumos the newer version is always tried first and the older 125# version only used if that is not accepted by the processor. This script 126# looks for instances of more than one microcode for a CPU and moves the older 127# version into the amd/fallback directory. Anyone using this tool to prepare a 128# PR is expected to make judicious use of "git" and "ucodeadm" to verify that 129# everything looks reasonable afterwards. 130 131function ucode_version { 132 printf "0x%s" $($UCODEADM -t amd -l $1 | tr -s ' ' | 133 awk -F'[ =]' '$4 == "Patch" {print $5}') 134} 135 136echo 137echo "** Relocating fallback microcode" 138echo 139 140for f in amd/*-01; do 141 bf=$(basename $f -01) 142 [[ -f "amd/$bf-00" ]] || errexit "$f has no -00 variant" 143 mv -f amd/$bf-00 amd/fallback/ 144 mv amd/$bf-{01,00} 145 # Verify that the fallback version is lower than the main just in case 146 # AMD reverse the order of the patches for any reason. 147 typeset -i fbver=$(ucode_version amd/fallback/$bf-00) 148 typeset -i mlver=$(ucode_version amd/$bf-00) 149 printf " %s - %X / %X\n" $bf $mlver $fbver 150 (( mlver > fbver )) || errexit "$bf - fallback is newer" 151done 152 153# Combine the equivalence tables from the different updates into one. 154# Each equivalence-table file is a sequence of 16-byte records with a 155# 16-byte terminator which is all zeros. To merge, we just concatenate 156# the unique non-terminator records and then add 16 bytes from /dev/zero. 157{ 158 for f in $tmp/out/*/equivalence-table; do 159 size=$($STAT -c %s $f) 160 ((size -= 16)) 161 dd if=$f bs=1 count=$size status=none 162 done | $XXD -c16 | cut -d\ -f2- | sort -u | $XXD -r -p 163 # Add terminator 164 dd if=/dev/zero bs=1 count=16 status=none 165} > amd/equivalence-table 166 167$PKGFMT -u $mf 168mv $mf $mf.tmp 169egrep -v "file path=$FW" $mf.tmp > $mf 170rm -f $mf.tmp 171 172for f in amd/*-*; do 173 [[ -f $f ]] || continue 174 bf=${f##*/} 175 echo "file path=$FW/$bf group=sys mode=0444 reboot-needed=true" >> $mf 176done 177 178for f in amd/fallback/*-*; do 179 bf=${f##*/} 180 echo "file path=$FW/fallback/$bf"\ 181 "group=sys mode=0444 reboot-needed=true" >> $mf 182done 183 184sed -i "/pkg.fmri.*microcode\/amd@/s/@[0-9]*/@$ver/" $mf 185 186$PKGFMT -fv2 $mf 187 188