blob: 9922420b811ce0b395d3d07f15bf0598f459f859 [file] [log] [blame]
#!/bin/bash
# This script monitors S0/S1 GPIO fault and detects errors from CPUs
#
# So far, there is no specification describes the behavior of LED when an error (a pattern is detected) occurs.
# So when detecting a pattern, we simply set the gpio fault flag and turn on the SYS LED.
#
# The Parttern will in the format:
# <minor_byte> <quite_gap_1second> <major_byte> <stop_condition_low_for_3seconds>
#
# Ex: pattern minor_byte=0x03, major_byte=0x02, you will see the waveform like
# _1010100...(quite gap, low for 1 second)..0111111111000000000111111111110000000000...(stop condition, low for 3 seconds)..
#
# Usage: <app_name> <socket 0/1>
#
# shellcheck source=/dev/null
source /usr/sbin/gpio-lib.sh
# global variables
error_flag='/tmp/gpio_fault'
# the command "cat /sys/class/gpio/gpio"$gpio_Id"/value" itself, takes 10ms~35ms to complete, depends on CPU loading
polling_minor_byte_rate=0
polling_major_byte_rate=200000
polling_rate=$polling_minor_byte_rate
# the mount of low to ensure that already get out of minor_byte and is in quite gap
# this value depends on the polling_minor_byte_rate
max_low_in_minor_byte=9
# the mount of low to ensure that already get out of major_byte and is in stop condition
# this value depends on the polling_major_byte_rate
max_low_in_major_byte=9
max_low=$max_low_in_minor_byte
# state machines:
# detecting_minor_byte=0
# detecting_major_byte=1
curr_state=0
minor_byte=0
major_byte=0
gpio_status=0
socket=$1
socket1_present=151
socket1_status=1
S0_fault_gpio='s0-fault-alert'
S1_fault_gpio='s1-fault-alert'
map_event_name() {
case $major_byte in
2)
event_major="FAULT_LED_BOOT_ERROR"
case $minor_byte in
1)
event_minor="SOC_BOOTDEV_INIT_SEC_ERROR"
;;
2)
event_minor="SECJMP_FAIL_ERROR"
;;
3)
event_minor="UART_INIT_WARN"
;;
4)
event_minor="UART_TX_WARN"
;;
5)
event_minor="SOC_ROMPATCH_BAD_ERROR"
;;
6)
event_minor="SOC_ROMPATCH_RANGE_ERROR"
;;
7)
event_minor="SPI_INIT_ERROR"
;;
8)
event_minor="SPI_TX_ERROR"
;;
9)
event_minor="SPINOR_UNKNOW_DEVICE_WARN"
;;
10)
event_minor="EEPROM_BAD_NVP_HEADER_WARN"
;;
11)
event_minor="EEPROM_BAD_NVP_FIELD_WARN"
;;
12)
event_minor="EEPROM_BAD_CHECKSUM_ERROR_WARN"
;;
13)
event_minor="I2C_DMA_ERROR"
;;
14)
event_minor="I2C_TIMEOUT_ERROR"
;;
15)
event_minor="SOC_BOOTDEV_SPI_LOAD_ERROR"
;;
16)
event_minor="SOC_BOOTDEV_AUTHENTICATION_ERROR"
;;
17)
event_minor="PCP_POWERUP_FAILED"
;;
18)
event_minor="PCP_POWERDOWN_FAILED"
;;
19)
event_minor="CPUPLL_INIT_FAILED"
;;
20)
event_minor="MESHPLL_INIT_FAILED"
;;
*)
event_minor="NOT_SUPPORT"
esac
;;
3)
event_major="FAULT_LED_FW_LOAD_ERROR"
case $minor_byte in
9)
event_minor="LFS_ERROR"
;;
*)
event_minor="NOT_SUPPORT"
esac
;;
4)
event_major="FAULT_LED_SECURITY_ERROR"
case $minor_byte in
1)
event_minor="SEC_INVALID_KEY_CERT"
;;
2)
event_minor="SEC_INVALID_CONT_CERT"
;;
3)
event_minor="SEC_INVALID_ROOT_KEY"
;;
4)
event_minor="SEC_INVALID_SECPRO_KEY"
;;
5)
event_minor="SEC_INVALID_KEY_CERT_SIG"
;;
6)
event_minor="SEC_INVALID_CONT_CERT_SIG"
;;
7)
event_minor="SEC_INVALID_IMAGE_HASH"
;;
8)
event_minor="SEC_INVALID_PRI_VERSION"
;;
9)
event_minor="SEC_HUK_MISMATCH"
;;
10)
event_minor="SEC_FUSE_BLOW_CERT_WITHOUT_SPECIAL_BOOT_PIN"
;;
11)
event_minor="SEC_INVALID_CERT_SUBTYPE_STRUCT"
;;
12)
event_minor="SEC_TMMCFG_FAIL"
;;
13)
event_minor="SEC_INVALID_LCS_FROM_EFUSE"
;;
14)
event_minor="SEC_EFUSE_WRITE_FAILED"
;;
15)
event_minor="SEC_INVALID_CERT_VALUE"
;;
16)
event_minor="SEC_INVALID_CERT_VERSION"
;;
*)
event_minor="NOT_SUPPORT"
;;
esac
;;
5)
event_major="FAULT_LED_EXCEPTION_ERROR"
case $minor_byte in
1)
event_minor="KERNEL_EXCEPTION_UNKNOWN_REASON_ERROR"
;;
2)
event_minor="KERNEL_EXCEPTION_HARD_FAULT_ERROR"
;;
3)
event_minor="KERNEL_EXCEPTION_BUS_FAULT_ERROR"
;;
4)
event_minor="KERNEL_EXCEPTION_MEMMANAGE_FAULT_ERROR"
;;
5)
event_minor="KERNEL_EXCEPTION_USAGE_FAULT_ERROR"
;;
*)
event_minor="NOT_SUPPORT"
;;
esac
;;
*)
event_major="NOT_SUPPORT"
;;
esac
}
set_unset_gpio_fault_flag() {
if [ ! -f $error_flag ] && [ "$1" == 1 ] ; then
touch $error_flag
elif [ -f $error_flag ] && [ "$1" == 0 ]; then
rm $error_flag
fi
}
toggle_state() {
if [ "$curr_state" == 0 ]; then
curr_state=1
polling_rate=$polling_major_byte_rate
else
curr_state=0
polling_rate=$polling_minor_byte_rate
map_event_name
echo "detected major_byte=$event_major, minor_byte=$event_minor"
set_unset_gpio_fault_flag 1
fi
}
save_pulse_of_byte() {
if [ "$curr_state" == 0 ]; then
minor_byte=$1
#echo "minor_byte=$1"
else
major_byte=$1
#echo "major_byte=$1"
fi
}
# we do not care the pulse is 50ms or 500ms, what we care is that the number of high pulses
cnt_falling_edge_in_byte() {
local cnt_falling_edge=0
local cnt_low=0
local prev=0
local curr=0
while true
do
prev=$curr
curr=$gpio_status
# count the falling edges, if they occur, just reset cnt_low
if [ "$prev" == 1 ] && [ "$curr" == 0 ]; then
cnt_falling_edge=$(( cnt_falling_edge + 1 ))
cnt_low=0
continue
# check if we are in the quite gap or stop condition
elif [ "$prev" == 0 ] && [ "$curr" == 0 ]; then
cnt_low=$(( cnt_low + 1 ))
if [ "$cnt_low" == "$max_low" ]; then
save_pulse_of_byte "$cnt_falling_edge"
toggle_state
break
fi
fi
usleep $polling_rate
gpio_status=$(cat /sys/class/gpio/gpio"$gpio_Id"/value)
done
}
gpio_config_input() {
echo "$gpio_Id" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio"${gpio_Id}"/direction
}
gpio_number() {
local offset
local gpioPin
local str
str=$(gpiofind "$1")
if [ "$?" == '1' ]; then
echo -1
else
gpioid=$(echo "$str"|cut -c 9)
offset=$(echo "$str"|cut -d " " -f 2)
gpioPin=$(("$offset" + ${AST2600_GPIO_BASE[$gpioid]}))
echo "$gpioPin"
fi
}
init_sysfs_fault_gpio() {
gpio_Id=$(gpio_number "$fault_gpio")
if [ "$gpio_Id" == "-1" ]; then
echo "Invalid GPIO number"
exit 1
fi
if [ -d /sys/class/gpio/gpio"$gpio_Id" ]; then
return
fi
gpio_config_input "$gpio_Id"
}
# init
if [ "$socket" == "0" ]; then
fault_gpio="$S0_fault_gpio"
else
socket1_status=$(gpioget 0 "$socket1_present")
if [ "$socket1_status" == 1 ]; then
echo "socket 1 not present"
exit 0
fi
fault_gpio=$S1_fault_gpio
fi
init_sysfs_fault_gpio
# daemon start
while true
do
# detect when pattern starts
if [ "$gpio_status" == 1 ]; then
if [ "$curr_state" == 0 ]; then
# detecting minor byte, set up minor byte variables
max_low=$max_low_in_minor_byte
polling_rate=$polling_minor_byte_rate
else
# detecting major byte, set up major byte variables
max_low=$max_low_in_major_byte
polling_rate=$polling_major_byte_rate
fi
# now, there is something on gpio, check if that is a byte pattern
cnt_falling_edge_in_byte
fi
usleep $polling_rate
gpio_status=$(cat /sys/class/gpio/gpio"$gpio_Id"/value)
done
exit 1