#!/usr/local/bin/cbsd
#v10.1.0
MYARG="mode"
MYOPTARG="jname ppt"
MYDESC="Manage bhyve ppt devices"
CBSDMODULE="bhyve"
ADDHELP="mode=list - show ppt\n\
mode=attach - attach ppt to jname\n\
mode=detach - detach ppt from jname\n\
ppt - ppt\n
"

. ${subrdir}/nc.subr

. ${cbsdinit}

. ${subrdir}/virtual.subr
. ${system}

device=$( ${PCICONF_CMD} -l | ${EGREP_CMD} -E "^ppt[0-9]+@" | ${WC_CMD} -l | ${AWK_CMD} '{printf $1}' )

[ -z "${device}" ] && err 1 "${N1_COLOR}No such ppt devices${N0_COLOR}"

for id in $( ${SEQ_CMD} 0 ${device} ); do
	eval $( ${PCICONF_CMD} -vl | ${GREP_CMD} -A4 ^ppt${id}@pci | ${GREP_CMD} -E "^ppt${id}@|vendor|device" | while read a; do
		prefix=$( substr --pos=0 --len=6 --str="$a" )
		case "${prefix}" in
			vendor)
				value=$( echo "${a}" | ${CUT_CMD} -d = -f 2 | ${TR_CMD} -d "'" )
				echo "vendor${id}=\"${value}\""
				;;
			device)
				value=$( echo "${a}" | ${CUT_CMD} -d = -f 2 | ${TR_CMD} -d "'" )
				echo "device${id}=\"${value}\""
				;;
			ppt*)
				value=$( echo  "${a}" | ${AWK_CMD} '{printf $1}' | ${TR_CMD} -d "a-z@" | ${CUT_CMD} -d : -f 2-4 | ${TR_CMD} ":" "/" )
				echo "ppt${id}=\"${value}\""
				;;
			*)
				;;
		esac
	done )
done

# export $device, $ppt, $vendor variable
# $1 - as ppt, e.g: 5/1/0
load_ppt()
{
	my_ppt="${1}"

	[ -z "${my_ppt}" ] && return 1

	device=
	ppt=
	vendor=

	local tmp_ppt

	for id in $( ${SEQ_CMD} 0 ${device} ); do
		tmp_ppt=

		eval tmp_ppt="\$ppt${id}"
		[ -z "${tmp_ppt}" ] && continue

		if [ "${my_ppt}" = "${tmp_ppt}" ]; then
			eval device="\$device${id}"
			eval vendor="\$vendor${id}"
		fi
	done

	export ppt="${my_ppt}"
}

# export tmp_jname as linked jail to $ppt
init_ppt_action()
{
	[ -z "${ppt}" ] && err 1 "${N1_COLOR}Please set: ${N2_COLOR}ppt=${N0_COLOR}"
	[ -z "${jname}" ] && err 1 "${N1_COLOR}Please set: ${N2_COLOR}jname=${N0_COLOR}"

	# check for PCI passthrough
	if check_dmar; then
		err 1 "${N1_COLOR}I/O MMU / VT-d not enabled. Check you hardware or BIOS setting${N0_COLOR}"
	fi

	. ${subrdir}/rcconf.subr
	[ $? -eq 1 ] && err 1 "${N1_COLOR}No such jail: ${N2_COLOR}${jname}${N0_COLOR}"
	[ "${emulator}" != "bhyve" ] && err 1 "${N1_COLOR}Only for bhyve type VMs${N0_COLOR}"

	load_ppt "${ppt}"
	[ -z "${ppt}" ] && err 1 "${N1_COLOR}No such ppt: ${N2_COLOR}${ppt}${N0_COLOR}"

	tmp_jname=$( cbsdsqlro local SELECT jname FROM bhyveppt WHERE ppt=\"${ppt}\" 2>/dev/null )
}

case "${mode}" in
	list)
		for id in $( ${SEQ_CMD} 0 ${device} ); do
			ppt=
			device=
			vendor=
			jname=0

			eval ppt="\$ppt${id}"
			[ -z "${ppt}" ] && continue

			eval device="\$device${id}"
			eval vendor="\$vendor${id}"

			jname=$( cbsdsqlro local SELECT jname FROM bhyveppt WHERE ppt=\"${ppt}\" 2>/dev/null )
			[ -z "${jname}" -o "${jname}" = "0" ] && jname="-"
			[ -n "${ppt}" ] && echo "${ppt} : ${device} : ${vendor} : ${jname}"
		done
		;;
	attach)
		init_ppt_action
		[ -n "${tmp_jname}" -a "${tmp_jname}" != "0" ] && err 1 "${N1_COLOR}ppt already used by: ${N2_COLOR}${tmp_jname}${N1_COLOR}. Please detach first${N0_COLOR}"

		cbsdsqlrw local "INSERT INTO bhyveppt ( ppt, device, vendor, jname ) VALUES ( \"${ppt}\", \"device\", \"${vendor}\", \"${jname}\" )"
		err 0 "${N1_COLOR}Attached${N0_COLOR}"
		;;
	detach)
		init_ppt_action

		[ -z "${tmp_jname}" -a "${tmp_jname}" = "0" ] && err 1 "${N1_COLOR}ppt is not attached: ${N2_COLOR}${ppt}${N1_COLOR}"

		cbsdsqlrw local "DELETE FROM bhyveppt WHERE ppt=\"${ppt}\""
		err 0 "${N1_COLOR}Dettached${N0_COLOR}"
		;;
	*)
		err 1 "${N1_COLOR}Unknown mode: ${N2_COLOR}${mode}${N0_COLOR}"
esac

exit 0
