#!/bin/bash
#chkconfig: 1235 80 30
#description: HCT config service script

VERSION=3.0.9-2512d11

#max supported number of processes
MAX_PROGRESS="128"
MAX_QEMU_NUM="0"

#CCP_NUM value can be: all | 1 | 2 | 3 | 4 | ... | max ccp num |
CCP_NUM="default"

#CCP_TYPE value can be: both | ntb | psp
CCP_TYPE="both"

#DRIVER_MOD value can be: ccp | hct | vfio-pci
DRIVER_MOD="hct"

#ccp devices array
declare -a CCP_DEVS
declare -a NTB_DEVS
declare -a PSP_DEVS

#master psp device
MASTER_PSP_CCP=

#hard file limit for process. "0" won't make any change.
HARD_FILE_LIMIT=0

#If numa ids are designated, ccp must be seated according to the designated numa
NUMA_FILTER=()

#unbind and rebind all pspccps other than master pspccp
NON_MRPSP_REBIND="false"

#run as root user mode
RUN_AS_ROOT="false"

#-------> system dirs and special files <---------
CURRENT_DIR=$(cd $(dirname $0)/../../; pwd)
LOCKFILE=/var/lock/subsys/hct.lock
HCT_INFO_LOG=/var/log/hct_info.log
MDEV_PATH="/sys/bus/mdev/devices/"
HCT_SCRIPT_DIR="${CURRENT_DIR}/hct/script"
ENGINE_DIR="${CURRENT_DIR}/lib64/engines-1.1/"
HCT_LIB_DIR="${CURRENT_DIR}/lib64/"
HCT_TEST_DIR="${CURRENT_DIR}/bin/"
HCT_SPEED_DIR="${CURRENT_DIR}/bin/"
HCTD_PIDFILE="/var/run/hctd.pid"

check_hctd_running() {
	if [ -f "$HCTD_PIDFILE" ]; then
		local pid=$(cat "$HCTD_PIDFILE")
		# 检查PID是否有效且进程是否真的在运行
		# kill -0 "$pid": 向进程发送信号0（不实际杀死进程），用于检查进程是否存在
		if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
			return 0
		else
			rm -f "$HCTD_PIDFILE"
			return 1
		fi
	else
		return 1
	fi
}

#------->>> NTBCCP or/and PSPCCP deviceid <<<---------
NTBCCP="1468\|14b8\|14d8"
PSPCCP="1456\|1486\|14a6\|14c6\|1537"
CCPALL=${NTBCCP}"\|"${PSPCCP}

#------->>> function definitions  <<<---------

#-------------------------------------
# get command opts
#-------------------------------------
_getopt() {
	ARGS=`getopt -o n:t:d:p:q:m:f:u:r:s --long ccp_num:,ccp_type:,script_dir:,max_prog:,max_qemu_num:,driver_mod:,max_file_limit:,spec_numa:,non_mrpsp_rebind:,run_as_root -- "$@"`
	if [ $? != 0 ]; then
	echo "Args error terminating..."
	exit 1
	fi

	eval set -- "${ARGS}"

	while true
	do
	case "$1" in
		-n|--ccp_num)
			CCP_NUM=$2;
			shift 2
			;;
		-t|--ccp_type)
			CCP_TYPE=$2;
			shift 2
			;;
		-d|--script_dir)
			HCT_SCRIPT_DIR=$2;
			shift 2
			;;
		-p|--max_prog)
			MAX_PROGRESS=$2;
			shift 2
			;;
		-q|--max_qemu_num)
			MAX_QEMU_NUM=$2;
			shift 2
			;;
		-m|--driver_mod)
			DRIVER_MOD=$2;
			shift 2
			;;
		-f|--max_file_limit)
			HARD_FILE_LIMIT=$2;
			shift 2
			;;
		-u|--spec_numa)
			NUMA_FILTER=($(parse_numas "$2"))
			if [ $? -ne 0 ]; then
				echo "Error: ${NUMA_FILTER[@]}"
				usage
				exit 1
			fi
			shift 2
			;;
		-r|--non_mrpsp_rebind)
			NON_MRPSP_REBIND="true"
			shift 1
			;;
		-s|--run_as_root)
			RUN_AS_ROOT="true";
			shift 1
			;;
		--)
			shift
			break
			;;
		*)
			echo "Parameter error, $1"
			exit 1
			;;
	esac
	done


	for arg in $@
	do
	echo "Invalid args $arg"
	echo "Terminating!"
	exit 1
	done

}

#-------------------------------------
# help messages for this service
#-------------------------------------
usage() {

	echo "
HYGON HCT CONFIG SERVICE

Version: $VERSION

Descript: manage hygon hct ccp binding & etc.

USAGE:
	#Start hct service with given parameters;
	start [-m --driver_mod] [-n --ccp_num] [-t --ccp_type] [-p --max_prog] [-f --max_file_limit] [-u --spec_numa] [-r --non_mrpsp_rebind] [-s --run_as_root]
		\"driver_mod\" select a driver that ccp devices bind to, for example, \"ccp\", \"hct\", \"vfio-pci\".
		\"ccp_num\" can be set to a number which no more than the number of CCP, or \"all\", \"default\". If set \"ccp_num\" to \"all\", please disable fTPM in BIOS at first.
		\"ccp_type\" can be \"both\", \"ntb\", \"psp\"
		\"spec_numa\" specify which numa nodes to enable ccp on, for example, \"2\", \"4,6\", \"1,3,5-7\". If no nodes is specified, it defaults to all nodes.
		\"non_mrpsp_rebind\" unbind all pspccp devices other than master pspccp and rebind again.
		\"run_as_root\" setting up the HCT runtime environment with root privileges.

	#Stop hct service and release ccp resources
	stop [-m --driver_mod]
	\"driver_mod\" select a driver that ccp devices bind to, for example, \"ccp\", \"hct\", \"vfio-pci\".

	#Rebind CCP by given parameters;  \"ccp_type\" can be \"both\", \"ntb\", \"psp\"
	rebind [-n --ccp_num [-t --ccp_type] [-p --max_prog]

	#Show hct info
	status

	#Create vccp device groups (only when hctd is running)
	#Uses hctd -g command to create VCCP devices
	vccp_create <group_num>

	#Show this message
	usage
"

}

#-------------------------------------
# create vccp devices by sending command to hctd
#-------------------------------------
create_vccp_devices() {
	local group_num=$1
	local HCTD_PATH="$CURRENT_DIR/bin/hctd"


	# Validate input
	if ! [[ "$group_num" =~ ^[1-9][0-9]*$ ]]; then
		echo "Error: Invalid group number '$group_num'. Must be a positive integer."
		return 1
	fi

	# Check if hctd is running
	if ! check_hctd_running; then
		echo "hctd daemon is not running. Trying to start it..."
		LD_LIBRARY_PATH="$HCT_LIB_DIR" "$HCTD_PATH"
		for i in {1..5}; do
			sleep 1
			if check_hctd_running; then
				break
			fi
		done
		if ! check_hctd_running; then
			echo "Failed to start hctd."
			return 1
		fi
	fi

	# Check if hctd executable exists
	if [ ! -x "$HCTD_PATH" ]; then
		echo "Error: hctd executable not found at $HCTD_PATH"
		return 1
	fi

	# Use hctd -g command to create vccp devices
	if LD_LIBRARY_PATH="$HCT_LIB_DIR" "$HCTD_PATH" -g "$group_num"; then
		echo "Successfully created ${group_num} vccp group(s)."
	else
		echo "Error: Failed to create vccp devices -g ${group_num}."
		return 1
	fi
}

# check and update the hard file limit in limits.conf
update_fd_limit() {
	# backup old config
	current_time=$(date "+%Y%m%d-%H%M%S")
	limit_file="/etc/security/limits.conf"
	backup_file="${limit_file}.bak-$current_time"
	cp "$limit_file" "$backup_file"

	local root_pattern="^root\s+hard\s+nofile\s+([0-9]+)"
	local general_pattern="^\s*hard\s+nofile\s+([0-9]+)$"

	local new_limit_file="${limit_file}.new"
	: > "$new_limit_file"

	root_configured=false
	general_configured=false

	while IFS= read -r line; do
		# check file limit for root
		if [[ $line =~ $root_pattern ]]; then
			local current_limit="${BASH_REMATCH[1]}"
			if [[ "$current_limit" =~ ^[0-9]+$ ]] && [ "$current_limit" -lt $HARD_FILE_LIMIT ]; then
				echo -e "#$line" >> "$new_limit_file"
				echo -e "root hard nofile $HARD_FILE_LIMIT" >> "$new_limit_file"
			else
				echo -e "$line" >> "$new_limit_file"
			fi
			root_configured=true
		# check file limit for general user
		elif [[ $line =~ $general_pattern ]]; then
			local current_limit="${BASH_REMATCH[1]}"
			if [[ "$current_limit" =~ ^[0-9]+$ ]] && [ "$current_limit" -lt $HARD_FILE_LIMIT ]; then
				echo -e "#$line" >> "$new_limit_file"
				echo -e "hard nofile $HARD_FILE_LIMIT" >> "$new_limit_file"
			else
				echo -e "$line" >> "$new_limit_file"
			fi
			general_configured=true
		else
			echo -e "$line" >> "$new_limit_file"
		fi
	done < "$limit_file"

	if ! $root_configured; then
		echo -e "root hard nofile $HARD_FILE_LIMIT" >> "$new_limit_file"
	fi
	if ! $general_configured; then
		echo -e "hard nofile $HARD_FILE_LIMIT" >> "$new_limit_file"
	fi
	mv "$new_limit_file" "$limit_file"
	echo "The backup of the original limits.conf has been created at $backup_file. Relogin shell or execute 'ulimit -Hn' to set file limit"
}

parse_numas_part() {
	local part="$1"
	local -a part_result=()

	max_numa_node=$(lscpu | grep "NUMA node(s):" | awk '{print $3 - 1}')
	if [ -z "${max_numa_node}" ]; then
		max_numa_node=0
	fi

	if [[ "$part" =~ ^[0-9]+-[0-9]+$ ]]; then
		# Handle range
		IFS='-' read -r start end <<< "$part"
		if [ "${end}" -gt "${max_numa_node}" ]; then
			echo "numa num: \"${end}\" is greater than the max numa of the system"
			return 1
		fi

		for ((i=start; i<=end; i++)); do
			part_result+=("$i")
		done
	elif [[ "$part" =~ ^[0-9]+$ ]]; then
		# Handle single number
		if [ "$part" -gt "${max_numa_node}" ]; then
			echo "numa num: \"$part\" is greater than the max numa of the system"
			return 1
		fi

		part_result+=("$part")
	else
		echo "numa num: \"$part\" is invalid!"
		return 1
	fi

	echo "${part_result[@]}"
}

# Function to parse the numas and convert to array
parse_numas() {
	local input="$1"
	local -a result=()

	IFS=',' read -r -a parts <<< "$input"
	for part in "${parts[@]}"; do
		tmp_result="$(parse_numas_part "$part")"
		if [ "$?" -ne 0 ]; then
			echo "${tmp_result}"
			return 1
		fi

		result+=(${tmp_result})
	done

	echo "${result[@]}"
}

# Function to retrieve the numa node to which the device belongs
get_ccp_numa() {
	bdf="$1"
	numa_node=$(cat /sys/bus/pci/devices/${bdf}/numa_node)
	if [ $? -ne 0 ]; then
		echo "invalid bdf:${bdf}!"
		exit 1
	fi
	echo "${numa_node}"
}

# Function to filter specific ccps from designated numas
filter_ccp_from_numa() {
	local -n ccps="$1"
	local -a filter_res=()

	for ccp in "${ccps[@]}"; do
		numa=$(get_ccp_numa ${ccp})
		for f_numa in "${NUMA_FILTER[@]}"; do
			if [[ "${numa}" -eq "${f_numa}" ]]; then
				filter_res+=("${ccp}")
			fi
		done
	done
	echo "${filter_res[@]}"
}

unbind_pspccp_except_master() {
	for DEV in ${PSP_DEVS[*]}; do
		if [ ${DEV} == "${MASTER_PSP_CCP}" ]; then
			continue
		fi
		${HCT_SCRIPT_DIR}/hct_ccp_bind.py --unbind ${DEV}
	done
}

restore_ccp_driver_state() {
	MDEV_PATH="/sys/bus/mdev/devices/"
	if [ -d $MDEV_PATH ]; then
		MDEVS=$(ls $MDEV_PATH)
		for MDEV in ${MDEVS} ; do
			echo 1 > /sys/bus/mdev/devices/${MDEV}/remove
		done
	fi

	DEVS=(`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${CCPALL} | grep -v "drv=ccp" | awk '{print $1}'`)
	for DEV in ${DEVS[*]} ; do
		${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=ccp ${DEV}
	done
}

config_ccp_driver_state() {
	#system ccp amount
	SYS_CCP_NUM=${#CCP_DEVS[@]}
	#system ntb ccp amount
	SYS_NTB_NUM=${#NTB_DEVS[@]}
	#system psp ccp amount
	SYS_PSP_NUM=${#PSP_DEVS[@]}

	local EFFECT_CCP_NUM=0
	local i=0
	case $CCP_TYPE in
	"both")
		if [ $CCP_NUM == "all" ] || [ $CCP_NUM == "default" ]; then
			CCP_NUM=$SYS_CCP_NUM
		else
			if [ $CCP_NUM -gt $SYS_CCP_NUM ]; then
				echo "Total ccp amount is $SYS_CCP_NUM, ccp_num paramter is $CCP_NUM, invalid!"
				exit 1
			fi
		fi

		for DEV in ${NTB_DEVS[*]}; do
			if [ $i -lt $CCP_NUM ]; then
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=ccp ${DEV}
				let EFFECT_CCP_NUM++
				let i++
			else
				break
			fi
		done

		for DEV in ${PSP_DEVS[*]}; do
			if [ $i -lt $CCP_NUM ]; then
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=ccp ${DEV}
				let EFFECT_CCP_NUM++
				let i++
			else
				break;
			fi
		done
		;;
	"ntb")
		if [ $CCP_NUM == "all" ] || [ $CCP_NUM == "default" ]; then
			CCP_NUM=$SYS_NTB_NUM
		else
			if [ $CCP_NUM -gt $SYS_NTB_NUM ]; then
				echo "Total ntbccp amount is $SYS_NTB_NUM, ccp_num paramter is $CCP_NUM, invalid!"
				exit 1
			fi
		fi

		for DEV in ${NTB_DEVS[*]}; do
			if [ $i -lt $CCP_NUM ]; then
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=ccp ${DEV}
				let EFFECT_CCP_NUM++
				let i++
			else
				break
			fi
		done
		;;
	"psp")
		if [ $CCP_NUM == "all" ] || [ $CCP_NUM == "default" ]; then
			CCP_NUM=$SYS_PSP_NUM
		else
			if [ $CCP_NUM -gt $SYS_PSP_NUM ]; then
				echo "Total pspccp amount is $SYS_PSP_NUM, ccp_num paramter is $CCP_NUM, invalid!"
				exit 1
			fi
		fi

		for DEV in ${PSP_DEVS[*]}; do
			if [ $i -lt $CCP_NUM ]; then
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=ccp ${DEV}
				let EFFECT_CCP_NUM++
				let i++
			else
				break
			fi
		done
		;;
	vccp_create)
		shift 1
		if [ -z "$1" ]; then
			echo "Error: Missing group number for vccp_create."
			usage
			exit 1
		fi
		create_vccp_devices "$1"
		;;
	*)
		usage
		exit 7
		;;
	esac

	if [ $EFFECT_CCP_NUM -eq 0 ]; then
		echo "The value of EFFECT_CCP_NUM is 0, invalid!"
		exit -2
	fi

	echo "${EFFECT_CCP_NUM} CCP devices are bound with ccp driver"
}

unbind_driver_from_ccp() {
	MDEV_PATH="/sys/bus/mdev/devices/"
	if [ -d $MDEV_PATH ]; then
		MDEVS=$(ls $MDEV_PATH)
		for MDEV in ${MDEVS} ; do
			echo 1 > /sys/bus/mdev/devices/${MDEV}/remove
		done
	fi

	DEVS=(`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${CCPALL} | grep -E "drv=hct|drv=vfio-pci" | awk '{print $1}'`)
	for DEV in ${DEVS[*]} ; do
		${HCT_SCRIPT_DIR}/hct_ccp_bind.py --unbind ${DEV}
	done
}

bind_driver_to_ccp() {
	#system ntb ccp amount
	SYS_NTB_NUM=${#NTB_DEVS[@]}
	#system psp ccp amount
	SYS_PSP_NUM=${#PSP_DEVS[@]}

	if [ "$CCP_NUM" != "all" ]; then
		if [ "$CCP_TYPE" != "psp" ] && ([ "$CCP_NUM" == "default" ] || [ "$CCP_NUM" -lt $(( $SYS_PSP_NUM + $SYS_NTB_NUM )) ]); then
			let SYS_PSP_NUM--
		fi
		if [ "$CCP_TYPE" == "psp" ] && ([ "$CCP_NUM" == "default" ] || [ "$CCP_NUM" -lt $(( $SYS_PSP_NUM )) ]); then
			let SYS_PSP_NUM--
		fi
	fi

	case $CCP_TYPE in
	"both")
		if [ $CCP_NUM == "all" ]; then
			for TPM_DEV in ${CCP_DEVS[*]} ; do
				if [ "${TPM_DEV}" != "${MASTER_PSP_CCP}" ]; then
					${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
				fi
			done
			if [[ ${MASTER_PSP_CCP} == 0000* ]]; then
				if [ -e "/dev/tpm0" ] || [ -e "/dev/tcm0" ]; then
					echo "The trusted computing module is enabled, skipping the binding of master pspccp."
				else
					${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${MASTER_PSP_CCP}
				fi
			fi
		elif [ $CCP_NUM == "default" ]; then
			for TPM_DEV in ${CCP_DEVS[*]} ; do
				# fTPM issue
				if [ ${TPM_DEV} = "${MASTER_PSP_CCP}" ]; then
					continue;
				fi
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
			done
		elif [ $(( $SYS_PSP_NUM + $SYS_NTB_NUM )) -ge $CCP_NUM ]; then
			local i=0
			for TPM_DEV in ${CCP_DEVS[*]} ; do
				if [ $CCP_NUM -le $(( $SYS_PSP_NUM + $SYS_NTB_NUM )) ] && [ ${TPM_DEV} = "${MASTER_PSP_CCP}" ]; then
						continue;
				fi
				let i++
				if [ $i -le $CCP_NUM ]; then
					${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
				else
					break
				fi
			done
		else
			echo "Error: Total available CCP amount for hct  is $(( $SYS_PSP_NUM + $SYS_NTB_NUM )) , ccp_num paramter:$CCP_NUM is too large or illegal!"
			exit -1
		fi
		;;
	"ntb")
		if [ $CCP_NUM == "all" ] || [ $CCP_NUM == "default" ]; then
			for TPM_DEV in ${NTB_DEVS[*]} ; do
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
			done
		elif [ $SYS_NTB_NUM -ge $CCP_NUM ]; then
			local i=0
			for TPM_DEV in ${NTB_DEVS[*]} ; do
				let i++
				if [ $i -le $CCP_NUM ]; then
					${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
				else
					break
				fi
			done
		else
			echo "Error: Total NTB CCP amount is $SYS_NTB_NUM , ccp_num paramter:$CCP_NUM is too large or illegal!"
			exit -1
		fi
		;;
	"psp")
		if [ $CCP_NUM == "default" ]; then
			for TPM_DEV in ${PSP_DEVS[*]} ; do
				if [ ${TPM_DEV} = "${MASTER_PSP_CCP}" ]; then
						continue;
				fi
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
			done
		elif [ $CCP_NUM == "all" ]; then
			for TPM_DEV in ${PSP_DEVS[*]} ; do
				${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
			done
		elif [ $SYS_PSP_NUM -ge $CCP_NUM ]; then
			local i=0
			for TPM_DEV in ${PSP_DEVS[*]} ; do
				if [ $SYS_PSP_NUM -gt $CCP_NUM ] && [ ${TPM_DEV} = "${MASTER_PSP_CCP}" ]; then
						continue;
				fi
				let i++
				if [ $i -le $CCP_NUM ]; then
					${HCT_SCRIPT_DIR}/hct_ccp_bind.py --bind=$DRIVER_MOD ${TPM_DEV}
				else
					break
				fi
			done
		else
			echo "Error: Total PSP CCP amount is $SYS_PSP_NUM , ccp_num paramter:$CCP_NUM is too large or illegal!"
			exit -1
		fi
		;;
	*)
	usage
		exit 7
		;;
	esac

	if [ ' '$DRIVER_MOD == " hct" ]; then
		EFFECT_CCP_NUM=`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${CCPALL} | grep "drv=hct" | awk 'END {print NR}'`
		#create mdev per progress
		echo "${EFFECT_CCP_NUM} CCP devices are bound with hct driver"
		MDEV_NUM=$((${EFFECT_CCP_NUM}*${MAX_PROGRESS}))
		if [[ $MDEV_NUM > 0 ]]; then
			for i in $(seq 1 ${MDEV_NUM}) ; do
				echo `uuidgen` > /sys/devices/virtual/hct/hct/mdev_supported_types/hct-1/create
			done
			echo "${MDEV_NUM} mdev devices are created to support max ${MAX_PROGRESS} progress"
		fi
		VIR_MDEV_NUM=$((${EFFECT_CCP_NUM}*${MAX_QEMU_NUM}))
		if [[ $VIR_MDEV_NUM > 0 ]]; then
			for i in $(seq 1 ${VIR_MDEV_NUM}) ; do
				uuid=$(uuidgen)
				echo $uuid > /sys/devices/virtual/hct/hct/mdev_supported_types/hct-1/create
				echo 1 > /sys/bus/mdev/devices/${uuid}/vendor/use
			done
			echo "${VIR_MDEV_NUM} mdev devices are created to support max ${MAX_QEMU_NUM} virtual machine"
		fi
	else
		EFFECT_CCP_NUM=`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${CCPALL} | grep "drv=vfio-pci" | awk 'END {print NR}'`
		echo "${EFFECT_CCP_NUM} CCP devices are bound with vfio-pci driver"
	fi
}

exec_tkm_dev_init() {
	local HAG_BIN_PATHS=(
		"/opt/hygon/bin/hag"
		"/usr/local/bin/hag"
		"/usr/bin/hag"
		"/bin/hag"
		"/sbin/hag"
		"/usr/sbin/hag"
		"${CURRENT_DIR}/bin/hag"
	)

	for path in "${HAG_BIN_PATHS[@]}"; do
		if [[ -x "$path" ]]; then
			$path tkm dev_init -m 128 > /dev/null || return $?
			return 0
		fi
	done

	echo "Not found hag! Please update the hag to the /opt/hygon/bin/ directory, see more https://openanolis.cn/sig/Hygon-Arch/doc/922794989388611818"
	return -1
}

set_other_user_permissions() {

	#chmod /dev/vfio/xx[group_id] to user permissions
	local VFIO_PATH=/dev/vfio
	for group_id in `ls ${VFIO_PATH}`;do
		if [ ' '${group_id} != " vfio" ]; then
			chmod go+rw ${VFIO_PATH}/${group_id}
		fi
	done

	# chmod pci resource2 to user permissions
	for PSP_DEV in ${PSP_DEVS[*]} ; do
		chmod go+r /sys/bus/pci/devices/${PSP_DEV}/resource2
	done

	#psp_dev_init cmmand failed, tkm cannot be configured with non-root privileges,
	#but ignore this error and retain the non-root privileges for cae.
	exec_tkm_dev_init || return 0

	# chmod tkm runtime environment to user permissions
	chmod go+rw /dev/hygon_psp_config &> /dev/null
	chmod go+rw /dev/hygon_psp_resource2 &> /dev/null
	chmod go+rw /etc/tkm_rootkey_img &> /dev/null
	chmod go+rw /etc/psp_config &> /dev/null
	chmod go+rw /etc/hct_config &> /dev/null
	chmod go+rw /dev/shm/hct_* &> /dev/null
	chmod go+rw /dev/shm/sdf_* &> /dev/null
	chmod go+rw /dev/hugepages/tkm_* &> /dev/null
	chmod go+r /sys/bus/node/devices/node*/hugepages/hugepages-*/free_hugepages
	chmod go+rw /sys/bus/node/devices/node*/hugepages/hugepages-*/nr_hugepages
}

#-------------------------------------
# service start function
#-------------------------------------
start() {
	_getopt "$@"

	if [ ' '$DRIVER_MOD != " ccp" ] && [ ' '$DRIVER_MOD != " hct" ] && [ ' '$DRIVER_MOD != " vfio-pci" ]; then
		echo "driver must be 'ccp' or 'hct' or 'vfio-pci'"
		exit 8
	fi

	if check_hctd_running && [ "$(systemd-detect-virt)" = "none" ]; then
		echo "The old hctd daemon process is still running. Please run hctconfig stop before start."
		exit 1
	fi

	modprobe vfio | modprobe vfio-pci | modprobe vfio_iommu_type1
	if [ $? -ne 0 ]; then
		echo "lack of basic kernel modules(vfio/vfio-pci/vfio_iommu_type1)!"
		exit 8
	fi

	if [ ' '$DRIVER_MOD == " hct" ]; then
		depmod | modprobe hct
		if [ $? -ne 0 ]; then
			echo "lack of necessary kernel modules hct!"
			exit 8
		fi
	fi

	MASTER_PSP_CCP=(`${HCT_SCRIPT_DIR}/hct_ccp_bind.py --get_master_pspccp | tail -n 1`)
	PLATFORM=$(sudo dmidecode -s system-manufacturer)
	if [[ $PLATFORM == "HYGON" ]] && [[ ! $MASTER_PSP_CCP == 0000* ]];then
		echo "get error MASTER_PSP_CCP"
		exit 1
	fi

	CCP_DEVS=(`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${CCPALL} | awk '{print $1}'`)
	NTB_DEVS=(`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${NTBCCP} | awk '{print $1}'`)
	PSP_DEVS=(`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${PSPCCP} | awk '{print $1}'`)

	# if specified numa nodes, filter all devs
	if [ ${#NUMA_FILTER[@]} -ne 0 ]; then
		CCP_DEVS=($(filter_ccp_from_numa CCP_DEVS))
		NTB_DEVS=($(filter_ccp_from_numa NTB_DEVS))
		PSP_DEVS=($(filter_ccp_from_numa PSP_DEVS))
	fi

	if [ ' '$DRIVER_MOD == " ccp" ]; then
		if [ ${NON_MRPSP_REBIND} == "true" ]; then
			unbind_pspccp_except_master
		fi
		unbind_driver_from_ccp
		config_ccp_driver_state
	elif [ ' '$DRIVER_MOD == " hct" ] || [ ' '$DRIVER_MOD == " vfio-pci" ]; then
		unbind_driver_from_ccp
		bind_driver_to_ccp
	else
		echo "DRIVER_MOD=$DRIVER_MOD, not support"
		exit 8
	fi

	if [[ $RUN_AS_ROOT == "false" ]]; then
		set_other_user_permissions
	fi

	# enable master psp's pci to support the hgsc checking
	if [[ $MASTER_PSP_CCP == 0000* ]]; then
		master_psp_status=`cat /sys/bus/pci/devices/${MASTER_PSP_CCP}/enable`
		if [ $master_psp_status -eq 0 ]; then
			echo 1 > /sys/bus/pci/devices/${MASTER_PSP_CCP}/enable
		fi
	fi

	if [ $HARD_FILE_LIMIT -gt 0 ]; then
		update_fd_limit
	fi

	if { [ ' '$DRIVER_MOD == " vfio-pci" ] || [ ' '$DRIVER_MOD == " ccp" ]; } && [ "$(systemd-detect-virt)" = "none" ]; then
		LD_LIBRARY_PATH=$HCT_LIB_DIR $CURRENT_DIR/bin/hctd
		for i in {1..5}; do
			sleep 1
			if check_hctd_running; then
				break
			fi
		done
		if check_hctd_running; then
			# Create vccp devices if MAX_QEMU_NUM is set
			if [ "$MAX_QEMU_NUM" -gt 0 ]; then
				create_vccp_devices "$MAX_QEMU_NUM"
			fi
		else
			echo "Failed to start hctd."
		fi
	fi
}

#-------------------------------------
# service stop function
#-------------------------------------
stop() {
	echo "Release CCPs..."

	if check_hctd_running && [ "$(systemd-detect-virt)" = "none" ]; then
		pid=$(cat $HCTD_PIDFILE)
		kill -TERM $pid
		# Check if hctd is closed, up to 5 seconds
		for i in {1..5}; do
			sleep 1
			if ! check_hctd_running; then
				break
			fi
		done
		if check_hctd_running; then
			echo "hctd is still running, please terminate it manually."
		else
			echo "hctd stopped successfully."
		fi
	fi
	rm /dev/shm/hct_gid_bitmap &> /dev/null
	rm /dev/shm/hct_gid_locks &> /dev/null
	rm /dev/shm/hct_global_share &> /dev/null
	rm /dev/shm/hct_host_share &> /dev/null

	_getopt "$@"

	# In the virtual machine, please select vfio-pci as the value of DRIVER_MOD.
	if [ ' '$DRIVER_MOD != " vfio-pci" ]; then
		restore_ccp_driver_state
	else
		unbind_driver_from_ccp
	fi
	hct_info=`lsmod |grep hct | awk 'END {print NR}'`
	if [ $hct_info -ne 0 ]; then
		rmmod hct
	fi
}

#-------------------------------------
# service restart function
#-------------------------------------
restart() {
	stop $*
	start $*
}


#-------------------------------------
# service status function
#-------------------------------------
status() {
	if [ -d `echo /sys/devices/virtual/hct/hct/mdev_supported_types/hct-1/devices` ];then
		MDEV_NUM=`ls -l /sys/devices/virtual/hct/hct/mdev_supported_types/hct-1/devices | grep -v "total" | wc -l`
		EFFECT_CCP_NUM=`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | sed -n '/drv=hct/p' | grep ${CCPALL} | awk 'END {print NR}'`
		MAX_PROGRESS=`expr ${MDEV_NUM} / ${EFFECT_CCP_NUM}`
	else
		EFFECT_CCP_NUM=`${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | sed -n '/drv=vfio-pci/p' | grep ${CCPALL} | awk 'END {print NR}'`
		MDEV_NUM=0
		MAX_PROGRESS=0
	fi
	echo "------------>>>  H C T	I N F O	D U M P  <<<--------------"
	echo ""
	printf "HCT Version:			%s\n"  $VERSION
	printf "HCT engine Dir:			%s\n"  $ENGINE_DIR
	printf "HCT lib Dir:			%s\n"  $HCT_LIB_DIR
	printf "HCT script Dir:			%s\n"  $HCT_SCRIPT_DIR
	printf "HCT function test tool Dir:	%s\n"  $HCT_TEST_DIR
	printf "HCT performance tool Dir:	%s\n"  $HCT_SPEED_DIR
	if [ $MDEV_NUM -ne 0 ]; then
		printf "HCT created %s mdev devices to support max %s progress \n"  $MDEV_NUM $MAX_PROGRESS
	else
		printf "Found %s CCP devices are bound with vfio-pci driver\n" $EFFECT_CCP_NUM
	fi
	echo ""
	printf "HCT CCP effective Binding info :\n"
	${HCT_SCRIPT_DIR}/hct_ccp_bind.py -s | grep ${CCPALL}
	echo ""
	echo "-----------------------------------------------------------------------------"
	echo ""


	printf "\n\n"
}

#-------------------------------------
# service rebind function
#-------------------------------------
rebind() {
	start $*
}


#==========================
# service entry
#==========================
process() {
	case $1 in
	start)
		shift 1
		start $*
		;;
	stop)
		shift 1
		stop $*
		;;
	restart)
		shift 1
		restart $*
		;;
	rebind)
		shift 1
		rebind $*
		;;
	status)
		status
		;;
	vccp_create)
		shift 1
		if [ -z "$1" ]; then
			echo "Error: Missing group number for vccp_create."
			usage
			exit 1
		fi
		create_vccp_devices "$1"
		;;
	*)
		usage
		exit 7
		;;
	esac
}

main() {
	if [ $# -lt 1 ]; then
		start ;
		exit 1
	fi

	process "$@"
}

main $*
