#!/bin/bash                                                                     
#   

# changelog
# 2017.11.07  ver 1.0    inital release
# 2017.11.10  ver 1.1    use mktemp

# get_cpu_vendor                                                                
# Only two values are returned: AMD or Intel                                    
get_cpu_vendor ()
{
    if grep -qE AMD /proc/cpuinfo; then
        printf "AMD"
    fi
    if grep -qE Intel /proc/cpuinfo; then
	printf "Intel"
    fi
}

# get_host_ucode                                                                
# Get the hosts' ucode file based on the /proc/cpuinfo                          
get_ucode_file ()
{
    local family=`grep -E "cpu family" /proc/cpuinfo | head -1 | sed s/.*:\ //`
    local model=`grep -E "model" /proc/cpuinfo |grep -v name | head -1 | sed s/\
.*:\ //`
    local stepping=`grep -E "stepping" /proc/cpuinfo | head -1 | sed s/.*:\ //`

    if [[ "$(get_cpu_vendor)" == "AMD" ]]; then
        # If family greater than or equal to 0x16                               
        if [[ $family -ge 22 ]]; then
            printf "microcode_amd_fam16h.bin"
        elif [[ $family -eq 21 ]]; then
            printf "microcode_amd_fam15h.bin"
        else
            printf "microcode_amd.bin"
        fi
    fi
    if [[ "$(get_cpu_vendor)" == "Intel" ]]; then
        # The /proc/cpuinfo are in decimal.                                     
        printf "%02x-%02x-%02x" ${family} ${model} ${stepping}
    fi
}

## usage
usage()
{
    echo `basename $0` : [-v -f] kernelversion
    echo "     Generate and Combine early microcode to initrd image"
    echo "     -v: verbose message output"
    echo "     -f: search microcode file only"
    echo `basename $0` : -V
    echo "     Print usage"
}

## main

[ $# -ne 1 -a $# -ne 2 ] && {
    usage
    exit
}

Tmp_dir=/tmp
Firmware_dir=/lib/firmware
AMD_Firmware_dir=$Firmware_dir/amd-ucode
Intel_Firmware_dir=$Firmware_dir/intel-ucode
Ucode_file=""
Fullpath_ucode_file=""
Verbose=""
Finding=""

while [ $# -gt 0 ]; do
    case $1 in
	-f)
	    Finding=yes
	        ;;
	-v)
	    Verbose=yes
	        ;;
	-V)
	    usage
	    exit
	        ;;
	*)
	    Version=$1
    esac
    shift
done

Ucode_file=$(get_ucode_file)
if [ $(get_cpu_vendor) == "AMD" ]; then
    [ -n "$Verbose" ] && echo "AMD CPU is found."
    if [ -f $AMD_Firmware_dir/$Ucode_file ]; then
	[ -n "$Verbose" ] && {
	    echo "Microcode file for your CPU is found."
	}
	Fullpath_ucode_file=$AMD_Firmware_dir/$Ucode_file
    else
	[ -n "$Verbose" ] && echo "Microcode file for your CPU is NOT found."
	exit
    fi
elif [ $(get_cpu_vendor) == "Intel" ]; then
    [ -n "$Verbose" ] && echo "Intel CPU is found."
    [ -d $Intel_Firmware_dir ] || {
	[ -n "$Verbose" ] && echo $Intel_Firmware_dir" is not found (not installed ?)"
	exit
    }
    if [ -f $Intel_Firmware_dir/$Ucode_file ]; then
	[ -n "$Verbose" ] && {
	    echo "Microcode file for your CPU is found."
	}
	Fullpath_ucode_file=$Intel_Firmware_dir/$Ucode_file
    else
	[ -n "$Verbose" ] && echo "Microcode file for your CPU is NOT found."
	exit
    fi
else
    echo "Not supported CPU Vendor"
    exit
fi

if [ -n "$Finding" ]; then
    echo $Fullpath_ucode_file
    exit
fi

[ ${EUID:-${UID}} = 0 ] || {
    echo "Need run superuser"
    echo ""
    usage
    exit
}

Base_initrd_file=/boot/initrd-$Version.img
[ -f $Base_initrd_file ] || {
    echo $Base_initrd_file is not found.
    exit
}
[ -n "$Verbose" ] && echo "Target initrd file  : "$Base_initrd_file
[ -n "$Verbose" ] && echo "Microcode file      : "$Fullpath_ucode_file

[ -d $Tmp_dir ] || {
    echo $Tmp_dir" is NOT found."
    exit
}
Work_home=`mktemp -d $Tmp_dir/initrd_XXXXX`
# Work_home=$Tmp_dir/initrd_XXXXX
Work_dir=$Work_home/tmp
[ "$Work_home" != "/" ] && rm -rf $Work_home
mkdir -p $Work_dir/kernel/x86/microcode

if [ $(get_cpu_vendor) == "AMD" ]; then
    cp $Fullpath_ucode_file \
	$Work_dir/kernel/x86/microcode/AuthenticAMD.bin
elif [ $(get_cpu_vendor) == "Intel" ]; then
    cp $Fullpath_ucode_file \
	$Work_dir/kernel/x86/microcode/GenuineIntel.bin
fi

pushd $Work_dir > /dev/null
echo "Create ucode image and combine initrd-"${Version}".img"
find . | cpio -o -H newc >../ucode.cpio 2>/dev/null
cd ..
# [ -n "$Verbose" ] && echo Combine ucode image : initrd-${Version}.img
cp -a /boot/initrd-${Version}.img initrd-${Version}_org.img 
cat ucode.cpio initrd-${Version}_org.img > /boot/initrd-${Version}.img
popd > /dev/null

[ "$Work_home" != "/" ] && rm -rf $Work_home
echo "Combined."
# end
