cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dev-needs.sh (6219B)


      1#! /bin/sh
      2# SPDX-License-Identifier: GPL-2.0
      3# Copyright (c) 2020, Google LLC. All rights reserved.
      4# Author: Saravana Kannan <saravanak@google.com>
      5
      6function help() {
      7	cat << EOF
      8Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
      9
     10This script needs to be run on the target device once it has booted to a
     11shell.
     12
     13The script takes as input a list of one or more device directories under
     14/sys/devices and then lists the probe dependency chain (suppliers and
     15parents) of these devices. It does a breadth first search of the dependency
     16chain, so the last entry in the output is close to the root of the
     17dependency chain.
     18
     19By default it lists the full path to the devices under /sys/devices.
     20
     21It also takes an optional modifier flag as the first parameter to change
     22what information is listed in the output. If the requested information is
     23not available, the device name is printed.
     24
     25  -c	lists the compatible string of the dependencies
     26  -d	lists the driver name of the dependencies that have probed
     27  -m	lists the module name of the dependencies that have a module
     28  -f	list the firmware node path of the dependencies
     29  -g	list the dependencies as edges and nodes for graphviz
     30  -t	list the dependencies as edges for tsort
     31
     32The filter options provide a way to filter out some dependencies:
     33  --allow-no-driver	By default dependencies that don't have a driver
     34			attached are ignored. This is to avoid following
     35			device links to "class" devices that are created
     36			when the consumer probes (as in, not a probe
     37			dependency). If you want to follow these links
     38			anyway, use this flag.
     39
     40  --exclude-devlinks	Don't follow device links when tracking probe
     41			dependencies.
     42
     43  --exclude-parents	Don't follow parent devices when tracking probe
     44			dependencies.
     45
     46EOF
     47}
     48
     49function dev_to_detail() {
     50	local i=0
     51	while [ $i -lt ${#OUT_LIST[@]} ]
     52	do
     53		local C=${OUT_LIST[i]}
     54		local S=${OUT_LIST[i+1]}
     55		local D="'$(detail_chosen $C $S)'"
     56		if [ ! -z "$D" ]
     57		then
     58			# This weirdness is needed to work with toybox when
     59			# using the -t option.
     60			printf '%05u\t%s\n' ${i} "$D" | tr -d \'
     61		fi
     62		i=$((i+2))
     63	done
     64}
     65
     66function already_seen() {
     67	local i=0
     68	while [ $i -lt ${#OUT_LIST[@]} ]
     69	do
     70		if [ "$1" = "${OUT_LIST[$i]}" ]
     71		then
     72			# if-statement treats 0 (no-error) as true
     73			return 0
     74		fi
     75		i=$(($i+2))
     76	done
     77
     78	# if-statement treats 1 (error) as false
     79	return 1
     80}
     81
     82# Return 0 (no-error/true) if parent was added
     83function add_parent() {
     84
     85	if [ ${ALLOW_PARENTS} -eq 0 ]
     86	then
     87		return 1
     88	fi
     89
     90	local CON=$1
     91	# $CON could be a symlink path. So, we need to find the real path and
     92	# then go up one level to find the real parent.
     93	local PARENT=$(realpath $CON/..)
     94
     95	while [ ! -e ${PARENT}/driver ]
     96	do
     97		if [ "$PARENT" = "/sys/devices" ]
     98		then
     99			return 1
    100		fi
    101		PARENT=$(realpath $PARENT/..)
    102	done
    103
    104	CONSUMERS+=($PARENT)
    105	OUT_LIST+=(${CON} ${PARENT})
    106	return 0
    107}
    108
    109# Return 0 (no-error/true) if one or more suppliers were added
    110function add_suppliers() {
    111	local CON=$1
    112	local RET=1
    113
    114	if [ ${ALLOW_DEVLINKS} -eq 0 ]
    115	then
    116		return 1
    117	fi
    118
    119	SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
    120	for SL in $SUPPLIER_LINKS;
    121	do
    122		SYNC_STATE=$(cat $SL/sync_state_only)
    123
    124		# sync_state_only links are proxy dependencies.
    125		# They can also have cycles. So, don't follow them.
    126		if [ "$SYNC_STATE" != '0' ]
    127		then
    128			continue
    129		fi
    130
    131		SUPPLIER=$(realpath $SL/supplier)
    132
    133		if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
    134		then
    135			continue
    136		fi
    137
    138		CONSUMERS+=($SUPPLIER)
    139		OUT_LIST+=(${CON} ${SUPPLIER})
    140		RET=0
    141	done
    142
    143	return $RET
    144}
    145
    146function detail_compat() {
    147	f=$1/of_node/compatible
    148	if [ -e $f ]
    149	then
    150		echo -n $(cat $f)
    151	else
    152		echo -n $1
    153	fi
    154}
    155
    156function detail_module() {
    157	f=$1/driver/module
    158	if [ -e $f ]
    159	then
    160		echo -n $(basename $(realpath $f))
    161	else
    162		echo -n $1
    163	fi
    164}
    165
    166function detail_driver() {
    167	f=$1/driver
    168	if [ -e $f ]
    169	then
    170		echo -n $(basename $(realpath $f))
    171	else
    172		echo -n $1
    173	fi
    174}
    175
    176function detail_fwnode() {
    177	f=$1/firmware_node
    178	if [ ! -e $f ]
    179	then
    180		f=$1/of_node
    181	fi
    182
    183	if [ -e $f ]
    184	then
    185		echo -n $(realpath $f)
    186	else
    187		echo -n $1
    188	fi
    189}
    190
    191function detail_graphviz() {
    192	if [ "$2" != "ROOT" ]
    193	then
    194		echo -n "\"$(basename $2)\"->\"$(basename $1)\""
    195	else
    196		echo -n "\"$(basename $1)\""
    197	fi
    198}
    199
    200function detail_tsort() {
    201	echo -n "\"$2\" \"$1\""
    202}
    203
    204function detail_device() { echo -n $1; }
    205
    206alias detail=detail_device
    207ALLOW_NO_DRIVER=0
    208ALLOW_DEVLINKS=1
    209ALLOW_PARENTS=1
    210
    211while [ $# -gt 0 ]
    212do
    213	ARG=$1
    214	case $ARG in
    215		--help)
    216			help
    217			exit 0
    218			;;
    219		-c)
    220			alias detail=detail_compat
    221			;;
    222		-m)
    223			alias detail=detail_module
    224			;;
    225		-d)
    226			alias detail=detail_driver
    227			;;
    228		-f)
    229			alias detail=detail_fwnode
    230			;;
    231		-g)
    232			alias detail=detail_graphviz
    233			;;
    234		-t)
    235			alias detail=detail_tsort
    236			;;
    237		--allow-no-driver)
    238			ALLOW_NO_DRIVER=1
    239			;;
    240		--exclude-devlinks)
    241			ALLOW_DEVLINKS=0
    242			;;
    243		--exclude-parents)
    244			ALLOW_PARENTS=0
    245			;;
    246		*)
    247			# Stop at the first argument that's not an option.
    248			break
    249			;;
    250	esac
    251	shift
    252done
    253
    254function detail_chosen() {
    255	detail $1 $2
    256}
    257
    258if [ $# -eq 0 ]
    259then
    260	help
    261	exit 1
    262fi
    263
    264CONSUMERS=($@)
    265OUT_LIST=()
    266
    267# Do a breadth first, non-recursive tracking of suppliers. The parent is also
    268# considered a "supplier" as a device can't probe without its parent.
    269i=0
    270while [ $i -lt ${#CONSUMERS[@]} ]
    271do
    272	CONSUMER=$(realpath ${CONSUMERS[$i]})
    273	i=$(($i+1))
    274
    275	if already_seen ${CONSUMER}
    276	then
    277		continue
    278	fi
    279
    280	# If this is not a device with a driver, we don't care about its
    281	# suppliers.
    282	if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
    283	then
    284		continue
    285	fi
    286
    287	ROOT=1
    288
    289	# Add suppliers to CONSUMERS list and output the consumer details.
    290	#
    291	# We don't need to worry about a cycle in the dependency chain causing
    292	# infinite loops. That's because the kernel doesn't allow cycles in
    293	# device links unless it's a sync_state_only device link. And we ignore
    294	# sync_state_only device links inside add_suppliers.
    295	if add_suppliers ${CONSUMER}
    296	then
    297		ROOT=0
    298	fi
    299
    300	if add_parent ${CONSUMER}
    301	then
    302		ROOT=0
    303	fi
    304
    305	if [ $ROOT -eq 1 ]
    306	then
    307		OUT_LIST+=(${CONSUMER} "ROOT")
    308	fi
    309done
    310
    311# Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
    312# isn't really stable.
    313dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
    314
    315exit 0