diff options
author | William A. Kennington III <wak@google.com> | 2021-03-03 07:24:57 +0300 |
---|---|---|
committer | William A. Kennington III <wak@google.com> | 2021-03-05 02:17:41 +0300 |
commit | 1b34b591af7a1bb14771f3d1ff8c6c5206ace969 (patch) | |
tree | eb92f8c562fdc937f7e35c718680510b6de66d81 /meta-google/recipes-google/ipmi/ipmi-fru-sh | |
parent | 969145bc4e7224eedf6ea03e6c3658364193125e (diff) | |
download | openbmc-1b34b591af7a1bb14771f3d1ff8c6c5206ace969.tar.xz |
meta-google: ipmi-fru-sh: Add library
This is a useful utility for doing one off FRU rewriting operations,
used when manufactured boards don't have correct eeproms contents.
Change-Id: I73ad4d14e088678f49ccf2a28138aa6356de56a0
Signed-off-by: William A. Kennington III <wak@google.com>
Diffstat (limited to 'meta-google/recipes-google/ipmi/ipmi-fru-sh')
-rw-r--r-- | meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh b/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh new file mode 100644 index 000000000..335e0b21c --- /dev/null +++ b/meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +[ -n "${ipmi_fru_init-}" ] && return + +IPMI_FRU_COMMON_HEADER_INTERNAL_OFFSET_IDX=1 +IPMI_FRU_COMMON_HEADER_CHASSIS_OFFSET_IDX=2 +IPMI_FRU_COMMON_HEADER_BOARD_OFFSET_IDX=3 +IPMI_FRU_COMMON_HEADER_PRODUCT_OFFSET_IDX=4 +IPMI_FRU_COMMON_HEADER_MULTI_RECORD_OFFSET_IDX=5 +IPMI_FRU_AREA_HEADER_SIZE_IDX=1 +IPMI_FRU_CHECKSUM_IDX=-1 + +of_name_to_eeproms() { + local names + if ! names="$(grep -xl "$1" /sys/bus/i2c/devices/*/of_node/name)"; then + echo "Failed to find eeproms with of_name '$1'" >&2 + return 1 + fi + echo "$names" | sed 's,/of_node/name$,/eeprom,' +} + +of_name_to_eeprom() { + local eeproms + eeproms="$(of_name_to_eeproms "$1")" || return + if (( "$(echo "$eeproms" | wc -l)" != 1 )); then + echo "Got more than one eeprom for '$1':" $eeproms >&2 + return 1 + fi + echo "$eeproms" +} + +checksum() { + local -n checksum_arr="$1" + local checksum=0 + for byte in "${checksum_arr[@]}"; do + checksum=$((checksum + byte)) + done + echo $((checksum & 0xff)) +} + +fix_checksum() { + local -n fix_checksum_arr="$1" + old_cksum=${fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]} + ((fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]-=$(checksum fix_checksum_arr))) + ((fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]&=0xff)) + printf 'Corrected %s checksum from 0x%02X -> 0x%02X\n' \ + "$1" "${old_cksum}" "${fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]}" >&2 +} + +read_bytes() { + local file="$1" + local offset="$2" + local size="$3" + + echo "Reading $file at $offset for $size" >&2 + dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \ + hexdump -v -e '1/1 "%d "' +} + +write_bytes() { + local file="$1" + local offset="$2" + local -n bytes_arr="$3" + + local hexstr + hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return + echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2 + printf "$hexstr" | dd of="$file" bs=1 seek=$offset 2>/dev/null +} + +read_header() { + local eeprom="$1" + local -n header_arr="$2" + + header_arr=($(read_bytes "$eeprom" 0 8)) || return + echo "Checking $eeprom FRU Header version" >&2 + # FRU header is always version 1 + (( header_arr[0] == 1 )) || return + echo "Checking $eeprom FRU Header checksum" >&2 + local sum + sum="$(checksum header_arr)" || return + # Checksums should be valid + (( sum == 0 )) || return 10 +} + +read_area() { + local eeprom="$1" + local offset="$2" + local -n area_arr="$3" + local area_size="${4-0}" + + offset=$((offset*8)) + area_arr=($(read_bytes "$eeprom" "$offset" 8)) || return + echo "Checking $eeprom $offset FRU Area version" >&2 + # FRU Area is always version 1 + (( area_arr[0] == 1 )) || return + if (( area_size == 0 )); then + area_size=${area_arr[$IPMI_FRU_AREA_HEADER_SIZE_IDX]} + fi + area_arr=($(read_bytes "$eeprom" "$offset" $((area_size*8)))) || return + echo "Checking $eeprom $offset FRU Area checksum" >&2 + local sum + sum="$(checksum area_arr)" || return + # Checksums should be valid + (( sum == 0 )) || return 10 +} + +ipmi_fru_init=1 +return 0 2>/dev/null +echo "ipmi-fru is a library, not executed directly" >&2 +exit 1 |