blob: 335e0b21ca128fa6049c653c8eb9409a4b524467 [file] [log] [blame]
William A. Kennington III1b34b592021-03-02 20:24:57 -08001#!/bin/bash
2# Copyright 2021 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16[ -n "${ipmi_fru_init-}" ] && return
17
18IPMI_FRU_COMMON_HEADER_INTERNAL_OFFSET_IDX=1
19IPMI_FRU_COMMON_HEADER_CHASSIS_OFFSET_IDX=2
20IPMI_FRU_COMMON_HEADER_BOARD_OFFSET_IDX=3
21IPMI_FRU_COMMON_HEADER_PRODUCT_OFFSET_IDX=4
22IPMI_FRU_COMMON_HEADER_MULTI_RECORD_OFFSET_IDX=5
23IPMI_FRU_AREA_HEADER_SIZE_IDX=1
24IPMI_FRU_CHECKSUM_IDX=-1
25
26of_name_to_eeproms() {
27 local names
28 if ! names="$(grep -xl "$1" /sys/bus/i2c/devices/*/of_node/name)"; then
29 echo "Failed to find eeproms with of_name '$1'" >&2
30 return 1
31 fi
32 echo "$names" | sed 's,/of_node/name$,/eeprom,'
33}
34
35of_name_to_eeprom() {
36 local eeproms
37 eeproms="$(of_name_to_eeproms "$1")" || return
38 if (( "$(echo "$eeproms" | wc -l)" != 1 )); then
39 echo "Got more than one eeprom for '$1':" $eeproms >&2
40 return 1
41 fi
42 echo "$eeproms"
43}
44
45checksum() {
46 local -n checksum_arr="$1"
47 local checksum=0
48 for byte in "${checksum_arr[@]}"; do
49 checksum=$((checksum + byte))
50 done
51 echo $((checksum & 0xff))
52}
53
54fix_checksum() {
55 local -n fix_checksum_arr="$1"
56 old_cksum=${fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]}
57 ((fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]-=$(checksum fix_checksum_arr)))
58 ((fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]&=0xff))
59 printf 'Corrected %s checksum from 0x%02X -> 0x%02X\n' \
60 "$1" "${old_cksum}" "${fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]}" >&2
61}
62
63read_bytes() {
64 local file="$1"
65 local offset="$2"
66 local size="$3"
67
68 echo "Reading $file at $offset for $size" >&2
69 dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \
70 hexdump -v -e '1/1 "%d "'
71}
72
73write_bytes() {
74 local file="$1"
75 local offset="$2"
76 local -n bytes_arr="$3"
77
78 local hexstr
79 hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return
80 echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2
81 printf "$hexstr" | dd of="$file" bs=1 seek=$offset 2>/dev/null
82}
83
84read_header() {
85 local eeprom="$1"
86 local -n header_arr="$2"
87
88 header_arr=($(read_bytes "$eeprom" 0 8)) || return
89 echo "Checking $eeprom FRU Header version" >&2
90 # FRU header is always version 1
91 (( header_arr[0] == 1 )) || return
92 echo "Checking $eeprom FRU Header checksum" >&2
93 local sum
94 sum="$(checksum header_arr)" || return
95 # Checksums should be valid
96 (( sum == 0 )) || return 10
97}
98
99read_area() {
100 local eeprom="$1"
101 local offset="$2"
102 local -n area_arr="$3"
103 local area_size="${4-0}"
104
105 offset=$((offset*8))
106 area_arr=($(read_bytes "$eeprom" "$offset" 8)) || return
107 echo "Checking $eeprom $offset FRU Area version" >&2
108 # FRU Area is always version 1
109 (( area_arr[0] == 1 )) || return
110 if (( area_size == 0 )); then
111 area_size=${area_arr[$IPMI_FRU_AREA_HEADER_SIZE_IDX]}
112 fi
113 area_arr=($(read_bytes "$eeprom" "$offset" $((area_size*8)))) || return
114 echo "Checking $eeprom $offset FRU Area checksum" >&2
115 local sum
116 sum="$(checksum area_arr)" || return
117 # Checksums should be valid
118 (( sum == 0 )) || return 10
119}
120
121ipmi_fru_init=1
122return 0 2>/dev/null
123echo "ipmi-fru is a library, not executed directly" >&2
124exit 1