Files
spectre-meltdown-checker/src/libs/360_cpu_smt.sh
2026-03-31 20:16:47 +00:00

225 lines
7.4 KiB
Bash

# vim: set ts=4 sw=4 sts=4 et:
is_hygon() {
parse_cpu_details
[ "$cpu_vendor" = HygonGenuine ] && return 0
return 1
}
# Check whether the CPU vendor is AMD
# Returns: 0 if AMD, 1 otherwise
is_amd() {
parse_cpu_details
[ "$cpu_vendor" = AuthenticAMD ] && return 0
return 1
}
# Check whether the CPU vendor is Intel
# Returns: 0 if Intel, 1 otherwise
is_intel() {
parse_cpu_details
[ "$cpu_vendor" = GenuineIntel ] && return 0
return 1
}
# Check whether SMT (HyperThreading) is enabled on the system
# Returns: 0 if SMT enabled, 1 otherwise
is_cpu_smt_enabled() {
local siblings cpucores
# SMT / HyperThreading is enabled if siblings != cpucores
if [ -e "$g_procfs/cpuinfo" ]; then
siblings=$(awk '/^siblings/ {print $3;exit}' "$g_procfs/cpuinfo")
cpucores=$(awk '/^cpu cores/ {print $4;exit}' "$g_procfs/cpuinfo")
if [ -n "$siblings" ] && [ -n "$cpucores" ]; then
if [ "$siblings" = "$cpucores" ]; then
return 1
else
return 0
fi
fi
fi
# we can't tell
return 2
}
# Check whether the current CPU microcode version is on Intel's blacklist
# Returns: 0 if blacklisted, 1 otherwise
is_ucode_blacklisted() {
local tuple model stepping ucode cpuid
parse_cpu_details
# if it's not an Intel, don't bother: it's not blacklisted
is_intel || return 1
# it also needs to be family=6
[ "$cpu_family" = 6 ] || return 1
# now, check each known bad microcode
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/intel.c#n105
# 2018-02-08 update: https://newsroom.intel.com/wp-content/uploads/sites/11/2018/02/microcode-update-guidance.pdf
# model,stepping,microcode
for tuple in \
$INTEL_FAM6_KABYLAKE,0x0B,0x80 \
$INTEL_FAM6_KABYLAKE,0x0A,0x80 \
$INTEL_FAM6_KABYLAKE,0x09,0x80 \
$INTEL_FAM6_KABYLAKE_L,0x0A,0x80 \
$INTEL_FAM6_KABYLAKE_L,0x09,0x80 \
$INTEL_FAM6_SKYLAKE_X,0x03,0x0100013e \
$INTEL_FAM6_SKYLAKE_X,0x04,0x02000036 \
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003a \
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003c \
$INTEL_FAM6_BROADWELL,0x04,0x28 \
$INTEL_FAM6_BROADWELL_G,0x01,0x1b \
$INTEL_FAM6_BROADWELL_D,0x02,0x14 \
$INTEL_FAM6_BROADWELL_D,0x03,0x07000011 \
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000025 \
$INTEL_FAM6_HASWELL_L,0x01,0x21 \
$INTEL_FAM6_HASWELL_G,0x01,0x18 \
$INTEL_FAM6_HASWELL,0x03,0x23 \
$INTEL_FAM6_HASWELL_X,0x02,0x3b \
$INTEL_FAM6_HASWELL_X,0x04,0x10 \
$INTEL_FAM6_IVYBRIDGE_X,0x04,0x42a \
$INTEL_FAM6_SANDYBRIDGE_X,0x06,0x61b \
$INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712; do
model=$(echo "$tuple" | cut -d, -f1)
stepping=$(($(echo "$tuple" | cut -d, -f2)))
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ]; then
ucode=$(($(echo "$tuple" | cut -d, -f3)))
if [ "$cpu_ucode" = "$ucode" ]; then
pr_debug "is_ucode_blacklisted: we have a match! ($cpu_model/$cpu_stepping/$cpu_ucode)"
return 0
fi
fi
done
# 2024-01-09 update: https://github.com/speed47/spectre-meltdown-checker/issues/475
# this time the tuple is cpuid,microcode
for tuple in \
0xB0671,0x119 \
0xB06A2,0x4119 \
0xB06A3,0x4119; do
cpuid=$(($(echo "$tuple" | cut -d, -f1)))
ucode=$(($(echo "$tuple" | cut -d, -f2)))
if [ "$cpu_cpuid" = "$cpuid" ] && [ "$cpu_ucode" = "$ucode" ]; then
pr_debug "is_ucode_blacklisted: we have a match! ($cpuid/$ucode)"
return 0
fi
done
pr_debug "is_ucode_blacklisted: no ($cpu_model/$cpu_stepping/$cpu_ucode)"
return 1
}
# Check whether the CPU is a Skylake/Kabylake family processor
# Returns: 0 if Skylake-family, 1 otherwise
is_skylake_cpu() {
# return 0 if yes, 1 otherwise
#if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
# boot_cpu_data.x86 == 6) {
# switch (boot_cpu_data.x86_model) {
# case INTEL_FAM6_SKYLAKE_MOBILE:
# case INTEL_FAM6_SKYLAKE_DESKTOP:
# case INTEL_FAM6_SKYLAKE_X:
# case INTEL_FAM6_KABYLAKE_MOBILE:
# case INTEL_FAM6_KABYLAKE_DESKTOP:
# return true;
parse_cpu_details
is_intel || return 1
[ "$cpu_family" = 6 ] || return 1
if [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ]; then
return 0
fi
return 1
}
# Check whether the CPU is vulnerable to empty RSB speculation
# Returns: 0 if vulnerable, 1 otherwise
is_vulnerable_to_empty_rsb() {
if is_intel && [ -z "$cap_rsba" ]; then
pr_warn "is_vulnerable_to_empty_rsb() called before ARCH CAPABILITIES MSR was read"
fi
if is_skylake_cpu || [ "$cap_rsba" = 1 ]; then
return 0
fi
return 1
}
# Check whether the CPU is from the AMD Zen family (Ryzen, EPYC, ...)
# Returns: 0 if Zen, 1 otherwise
is_zen_cpu() {
parse_cpu_details
is_amd || return 1
[ "$cpu_family" = 23 ] && return 0
return 1
}
# Check whether the CPU is a Hygon Moksha (Dhyana) family processor
# Returns: 0 if Moksha, 1 otherwise
is_moksha_cpu() {
parse_cpu_details
is_hygon || return 1
[ "$cpu_family" = 24 ] && return 0
return 1
}
# Encode an AMD family/model/stepping range into a single integer (mimics Linux AMD_MODEL_RANGE macro)
# Args: $1=family $2=model_start $3=stepping_start $4=model_end $5=stepping_end
amd_model_range() {
echo $((($1 << 24) | ($2 << 16) | ($3 << 12) | ($4 << 4) | ($5)))
}
# Check if the current AMD CPU falls within a given model/stepping range (mimics Linux amd_legacy_erratum)
# Args: $1=range (output of amd_model_range)
# Returns: 0 if CPU is in range, 1 otherwise
amd_legacy_erratum() {
local range ms
range="$1"
ms=$((cpu_model << 4 | cpu_stepping))
if [ "$cpu_family" = $((((range) >> 24) & 0xff)) ] &&
[ $ms -ge $((((range) >> 12) & 0xfff)) ] &&
[ $ms -le $(((range) & 0xfff)) ]; then
return 0
fi
return 1
}
# Check whether the CPU has a microcode version that fixes Zenbleed
# Sets: g_zenbleed_fw, g_zenbleed_fw_required
# Returns: 0=fixed, 1=not fixed, 2=not applicable
has_zenbleed_fixed_firmware() {
local tuples tuple model_low model_high fwver
# return cached data
[ -n "$g_zenbleed_fw" ] && return "$g_zenbleed_fw"
# or compute it:
g_zenbleed_fw=2 # unknown
# only amd
if ! is_amd; then
g_zenbleed_fw=1
return $g_zenbleed_fw
fi
# list of known fixed firmwares, from commit 522b1d69219d8f083173819fde04f994aa051a98
tuples="
0x30,0x3f,0x0830107a
0x60,0x67,0x0860010b
0x68,0x6f,0x08608105
0x70,0x7f,0x08701032
0xa0,0xaf,0x08a00008
"
for tuple in $tuples; do
model_low=$(echo "$tuple" | cut -d, -f1)
model_high=$(echo "$tuple" | cut -d, -f2)
fwver=$(echo "$tuple" | cut -d, -f3)
if [ $((cpu_model)) -ge $((model_low)) ] && [ $((cpu_model)) -le $((model_high)) ]; then
if [ $((cpu_ucode)) -ge $((fwver)) ]; then
g_zenbleed_fw=0 # true
break
else
g_zenbleed_fw=1 # false
g_zenbleed_fw_required=$fwver
fi
fi
done
unset tuples
return $g_zenbleed_fw
}