refactor: rewrite read_cpuid to get more common code parts between BSD and Linux

This commit is contained in:
Stéphane Lesimple 2018-04-05 00:06:24 +02:00
parent 0919f5c236
commit 7a4ebe8009
1 changed files with 53 additions and 63 deletions

View File

@ -755,10 +755,19 @@ load_cpuid()
read_cpuid()
{
# leaf is the value of the eax register when calling the cpuid instruction:
_leaf="$1"
_bytenum="$2"
_and_operand="$3"
# eax=1 ebx=2 ecx=3 edx=4:
_register="$2"
# number of bits to shift the register right to:
_shift="$3"
# mask to apply as an AND operand to the shifted register value
_mask="$4"
# wanted value (optional), if present we return 0(true) if the obtained value is equal, 1 otherwise:
_wanted="$5"
# in any case, the read value is globally available in $read_cpuid_value
read_cpuid_value=''
if [ ! -e /dev/cpu/0/cpuid ] && [ ! -e /dev/cpuctl0 ]; then
# try to load the module ourselves (and remember it so we can rmmod it afterwards)
load_cpuid
@ -768,61 +777,39 @@ read_cpuid()
# Linux
# we need _leaf to be converted to decimal for dd
_leaf=$(( _leaf ))
if [ "$opt_verbose" -ge 3 ]; then
dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 >/dev/null 2>/dev/null
_debug "cpuid: reading leaf$_leaf of cpuid on cpu0, ret=$?"
_debug "cpuid: leaf$_leaf eax-ebx-ecx-edx: $( dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | od -x -A n)"
fi
# getting proper byte of edx on leaf$_leaf of cpuinfo in decimal
_reg_byte=$(dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip="$_bytenum" count=1 2>/dev/null | od -t u1 -A n | awk '{print $1}')
_debug "cpuid: leaf$_leaf byte $_bytenum: $_reg_byte (decimal)"
_reg_bit=$(( _reg_byte & _and_operand ))
_debug "cpuid: leaf$_leaf byte $_bytenum & $_and_operand = $_reg_bit"
[ "$_reg_bit" -eq 0 ] && return 1
# $_reg_bit is > 0, so the bit was found: return true (aka 0)
return 0
_cpuid=$(dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | od -A n -t u4)
elif [ -e /dev/cpuctl0 ]; then
# BSD
_cpuid=$(cpucontrol -i "$_leaf" /dev/cpuctl0 2>/dev/null | awk '{print $4,$5,$6,$7}')
# cpuid level 0x1: 0x000306d4 0x00100800 0x4dfaebbf 0xbfebfbff
_debug "cpuid: got $_cpuid for leaf $_leaf"
if [ "$_bytenum" -lt 4 ]; then
_reg_byte=$(echo "$_cpuid" | awk '{print $1}')
_debug "cpuid: $_bytenum is part of EAX ($_reg_byte)"
elif [ "$_bytenum" -lt 8 ]; then
_reg_byte=$(echo "$_cpuid" | awk '{print $2}')
_debug "cpuid: $_bytenum is part of EBX ($_reg_byte)"
elif [ "$_bytenum" -lt 12 ]; then
_reg_byte=$(echo "$_cpuid" | awk '{print $3}')
_debug "cpuid: $_bytenum is part of ECX ($_reg_byte)"
elif [ "$_bytenum" -lt 16 ]; then
_reg_byte=$(echo "$_cpuid" | awk '{print $4}')
_debug "cpuid: $_bytenum is part of EDX ($_reg_byte)"
else
_warn "read_cpuid: error in the program, please report to the developer ($_leaf/$_bytenum/$_and_operand)"
exit 1
fi
_bytenum=$(( _bytenum % 4 ))
case "$_bytenum" in
0) _reg_byte=0x$(echo "$_reg_byte" | cut -c9-10) ;;
1) _reg_byte=0x$(echo "$_reg_byte" | cut -c7-8) ;;
2) _reg_byte=0x$(echo "$_reg_byte" | cut -c5-6) ;;
3) _reg_byte=0x$(echo "$_reg_byte" | cut -c3-4) ;;
*) exit 8;
esac
_debug "cpuid: wanted byte is $_reg_byte"
# convert to decimal
_reg_byte=$(( _reg_byte ))
_debug "cpuid: decimal value is $_reg_byte"
_reg_bit=$(( _reg_byte & _and_operand ))
_debug "cpuid: leaf$_leaf byte $_bytenum & $_and_operand = $_reg_bit"
[ "$_reg_bit" -eq 0 ] && return 1
# $_reg_bit is > 0, so the bit was found: return true (aka 0)
return 0
else
return 2
fi
return 2
_debug "cpuid: leaf$_leaf on cpu0, eax-ebx-ecx-edx: $_cpuid"
[ -z "$_cpuid" ] && return 2
# get the value of the register we want
_reg=$(echo "$_cpuid" | awk '{print $'"$_register"'}')
# Linux returns it as decimal, BSD as hex, normalize to decimal
_reg=$(( _reg ))
# shellcheck disable=SC2046
_debug "cpuid: wanted register ($_register) has value $_reg aka "$(printf "%08x" "$_reg")
_reg_shifted=$(( _reg >> _shift ))
# shellcheck disable=SC2046
_debug "cpuid: shifted value by $_shift is $_reg_shifted aka "$(printf "%x" "$_reg_shifted")
read_cpuid_value=$(( _reg_shifted & _mask ))
# shellcheck disable=SC2046
_debug "cpuid: after AND $_mask, final value is $read_cpuid_value aka "$(printf "%x" "$read_cpuid_value")
if [ -n "$_wanted" ]; then
_debug "cpuid: wanted $_wanted and got $read_cpuid_value"
if [ "$read_cpuid_value" = "$_wanted" ]; then
return 0
else
return 1
fi
fi
return 0
}
dmesg_grep()
@ -1312,13 +1299,15 @@ write_msr()
return $ret
}
# $1 - msr number
# $2 - cpu index
read_msr()
{
# _msr must be in hex, in the form 0x1234:
_msr="$1"
# cpu index, starting from 0:
_cpu="$2"
read_msr_value=''
if [ "$os" != Linux ]; then
_msr=$(cpucontrol -m "$1" "/dev/cpuctl$2" 2>/dev/null); ret=$?
_msr=$(cpucontrol -m "$_msr" "/dev/cpuctl$_cpu" 2>/dev/null); ret=$?
[ $ret -ne 0 ] && return 1
# MSR 0x10: 0x000003e1 0xb106dded
_msr_h=$(echo "$_msr" | awk '{print $3}');
@ -1328,14 +1317,15 @@ read_msr()
read_msr_value="$_msr_h $_msr_l"
else
# convert to decimal
_msrindex=$(( $1 ))
if [ ! -r /dev/cpu/"$2"/msr ]; then
_msr=$(( _msr ))
if [ ! -r /dev/cpu/"$_cpu"/msr ]; then
return 200 # permission error
fi
if ! dd if=/dev/cpu/"$2"/msr bs=8 count=1 skip="$_msrindex" iflag=skip_bytes >/dev/null 2>&1; then
read_msr_value=$(dd if=/dev/cpu/"$_cpu"/msr bs=8 count=1 skip="$_msr" iflag=skip_bytes 2>/dev/null | od -t u1 -A n)
if [ -z "$read_msr_value" ]; then
# MSR doesn't exist, don't check for $? because some versions of dd still return 0!
return 1
fi
read_msr_value=$(dd if=/dev/cpu/"$2"/msr bs=8 count=1 skip="$_msrindex" iflag=skip_bytes 2>/dev/null | od -t u1 -A n)
fi
_debug "read_msr: MSR=$1 value is $read_msr_value"
return 0
@ -1402,7 +1392,7 @@ check_cpu()
_info_nol " * CPU indicates IBRS capability: "
# from kernel src: { X86_FEATURE_SPEC_CTRL, CPUID_EDX,26, 0x00000007, 0 },
read_cpuid 0x7 15 4; ret=$?
read_cpuid 0x7 4 26 1 1; ret=$?
if [ $ret -eq 0 ]; then
pstatus green YES "SPEC_CTRL feature bit"
cpuid_spec_ctrl=1
@ -1469,7 +1459,7 @@ check_cpu()
_info_nol " * CPU indicates IBPB capability: "
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
read_cpuid 0x80000008 5 16; ret=$?
read_cpuid 0x80000008 2 12 1 1; ret=$?
if [ $ret -eq 0 ]; then
pstatus green YES "IBPB_SUPPORT feature bit"
elif [ "$cpuid_spec_ctrl" = 1 ]; then
@ -1493,7 +1483,7 @@ check_cpu()
_info_nol " * CPU indicates STIBP capability: "
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
read_cpuid 0x7 15 8; ret=$?
read_cpuid 0x7 4 27 1 1; ret=$?
if [ $ret -eq 0 ]; then
pstatus green YES
elif [ $ret -eq 2 ]; then
@ -1505,8 +1495,8 @@ check_cpu()
_info " * Enhanced IBRS (IBRS_ALL)"
_info_nol " * CPU indicates ARCH_CAPABILITIES MSR availability: "
cpuid_arch_capabilities=-1
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
read_cpuid 0x7 15 32; ret=$?
# A processor supports the ARCH_CAPABILITIES MSR if it enumerates CPUID (EAX=7H,ECX=0):EDX[29] as 1
read_cpuid 0x7 4 29 1 1; ret=$?
if [ $ret -eq 0 ]; then
pstatus green YES
cpuid_arch_capabilities=1