From 1b34b591af7a1bb14771f3d1ff8c6c5206ace969 Mon Sep 17 00:00:00 2001 From: "William A. Kennington III" Date: Tue, 2 Mar 2021 20:24:57 -0800 Subject: 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 --- meta-google/recipes-google/ipmi/ipmi-fru-sh.bb | 16 +++ meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh | 124 +++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 meta-google/recipes-google/ipmi/ipmi-fru-sh.bb create mode 100644 meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh (limited to 'meta-google') diff --git a/meta-google/recipes-google/ipmi/ipmi-fru-sh.bb b/meta-google/recipes-google/ipmi/ipmi-fru-sh.bb new file mode 100644 index 000000000..deaee7aac --- /dev/null +++ b/meta-google/recipes-google/ipmi/ipmi-fru-sh.bb @@ -0,0 +1,16 @@ +SUMMARY = "Shell functions for manipulating IPMI formatted EEPROMs" +PR = "r1" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += "file://lib.sh" +S = "${WORKDIR}" + +DATA = "${datadir}/ipmi-fru" +FILES_${PN} += "${DATA}" + +do_install_append() { + install -d -m0755 ${D}${DATA} + install -m0644 lib.sh ${D}${DATA}/ +} 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 -- cgit v1.2.3