1#!/bin/bash
2#
3# Copyright (C) 2022 Intel Corporation.
4#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7
8# Helper functions
9
10function probe_modules() {
11    modprobe pci_stub
12}
13
14function offline_cpus() {
15    # Each parameter of this function is considered the APIC ID (as is reported in /proc/cpuinfo, in decimal) of a CPU
16    # assigned to a post-launched RTVM.
17    for i in $*; do
18        processor_id=$(grep -B 15 "apicid.*: ${i}$" /proc/cpuinfo | grep "^processor" | head -n 1 | cut -d ' ' -f 2)
19        if [ -z ${processor_id} ]; then
20            continue
21        fi
22        if [ "${processor_id}" = "0" ]; then
23            echo "Warning: processor 0 can't be offline, there may be unexpect error!" >> /dev/stderr
24            continue
25        fi
26        cpu_path="/sys/devices/system/cpu/cpu${processor_id}"
27        if [ -f ${cpu_path}/online ]; then
28            online=`cat ${cpu_path}/online`
29            echo cpu${processor_id} online=${online} >> /dev/stderr
30            if [ "${online}" = "1" ]; then
31                echo 0 > ${cpu_path}/online
32                online=`cat ${cpu_path}/online`
33                # during boot time, cpu hotplug may be disabled by pci_device_probe during a pci module insmod
34                while [ "${online}" = "1" ]; do
35                    sleep 1
36                    echo 0 > ${cpu_path}/online
37                    online=`cat ${cpu_path}/online`
38                done
39                echo ${processor_id} > /sys/devices/virtual/misc/acrn_hsm/remove_cpu
40            fi
41        fi
42    done
43}
44
45function unbind_device() {
46    physical_bdf=$1
47
48    vendor_id=$(cat /sys/bus/pci/devices/${physical_bdf}/vendor)
49    device_id=$(cat /sys/bus/pci/devices/${physical_bdf}/device)
50
51    echo $(printf "%04x %04x" ${vendor_id} ${device_id}) > /sys/bus/pci/drivers/pci-stub/new_id
52    echo ${physical_bdf} > /sys/bus/pci/devices/${physical_bdf}/driver/unbind
53    echo ${physical_bdf} > /sys/bus/pci/drivers/pci-stub/bind
54}
55
56function create_tap() {
57    # create a unique tap device for each VM
58    tap=$1
59    tap_exist=$(ip a show dev $tap)
60    if [ "$tap_exist"x != "x" ]; then
61        echo "$tap TAP device already available, reusing it."
62    else
63        ip tuntap add dev $tap mode tap
64    fi
65
66    # if acrn-br0 exists, add VM's unique tap device under it
67    br_exist=$(ip a | grep acrn-br0 | awk '{print $1}')
68    if [ "$br_exist"x != "x" -a "$tap_exist"x = "x" ]; then
69        echo "acrn-br0 bridge already exists, adding new $tap TAP device to it..."
70        ip link set "$tap" master acrn-br0
71        ip link set dev "$tap" down
72        ip link set dev "$tap" up
73    fi
74}
75
76function mount_partition() {
77    partition=$1
78
79    tmpdir=`mktemp -d`
80    mount ${partition} ${tmpdir}
81    echo ${tmpdir}
82}
83
84function unmount_partition() {
85    tmpdir=$1
86
87    umount ${tmpdir}
88    rmdir ${tmpdir}
89}
90
91# Generators of device model parameters
92
93function add_cpus() {
94    # Each parameter of this function is considered the apicid of processor (as is reported in /proc/cpuinfo) of
95    # a CPU assigned to a post-launched RTVM.
96
97    if [ "${vm_type}" = "RTVM" ] || [ "${scheduler}" = "SCHED_NOOP" ] || [ "${own_pcpu}" = "y" ]; then
98        offline_cpus $*
99    fi
100
101    cpu_list=$(local IFS=, ; echo "$*")
102    echo -n "--cpu_affinity ${cpu_list}"
103}
104
105function add_interrupt_storm_monitor() {
106    threshold_per_sec=$1
107    probe_period_in_sec=$2
108    inject_delay_in_ms=$3
109    delay_duration_in_ms=$4
110
111    echo -n "--intr_monitor ${threshold_per_sec},${probe_period_in_sec},${inject_delay_in_ms},${delay_duration_in_ms}"
112}
113
114function add_logger_settings() {
115    loggers=()
116
117    for conf in $*; do
118        logger=${conf%=*}
119        level=${conf#*=}
120        loggers+=("${logger},level=${level}")
121    done
122
123    cmd_param=$(local IFS=';' ; echo "${loggers[*]}")
124    echo -n "--logger_setting ${cmd_param}"
125}
126
127function add_virtual_device() {
128    slot=$1
129    kind=$2
130    options=$3
131
132    if [ "${kind}" = "virtio-net" ]; then
133        # Create the tap device
134        if [[ ${options} =~ tap=([^,]+) ]]; then
135            tap_conf="${BASH_REMATCH[1]}"
136            create_tap "${tap_conf}" >&2
137        fi
138    fi
139
140    if [ "${kind}" = "virtio-input" ]; then
141        options=$*
142        if [[ "${options}" =~ id:([a-zA-Z0-9_\-]*) ]]; then
143            unique_identifier="${BASH_REMATCH[1]}"
144            options=${options/",id:${unique_identifier}"/''}
145        fi
146
147        if [[ "${options}" =~ (Device name: )(.*),( Device physical path: )(.*) ]]; then
148            device_name="${BASH_REMATCH[2]}"
149            phys_name="${BASH_REMATCH[4]}"
150            local IFS=$'\n'
151            device_name_paths=$(grep -r "${device_name}" /sys/class/input/event*/device/name)
152            phys_paths=$(grep -r "${phys_name}" /sys/class/input/event*/device/phys)
153        fi
154
155        if [ -n "${device_name_paths}" ] && [ -n "${phys_paths}" ]; then
156            for device_path in ${device_name_paths}; do
157                for phys_path in ${phys_paths}; do
158                    if [ "${device_path%/device*}" = "${phys_path%/device*}" ]; then
159                        event_path=${device_path}
160                        if [[ ${event_path} =~ event([0-9]+) ]]; then
161                            event_num="${BASH_REMATCH[1]}"
162                            options="/dev/input/event${event_num}"
163                            break
164                        fi
165                    fi
166                done
167            done
168        fi
169
170        if [[ ${options} =~ event([0-9]+) ]]; then
171            echo "${options} input device path is available in the service vm." >> /dev/stderr
172        else
173            echo "${options} input device path is not found in the service vm." >> /dev/stderr
174            return
175        fi
176
177        if [ -n "${options}" ] && [ -n "${unique_identifier}" ]; then
178            options="${options},${unique_identifier}"
179        fi
180
181    fi
182
183    echo -n "-s ${slot},${kind}"
184    if [ -n "${options}" ]; then
185        echo -n ",${options}"
186    fi
187}
188
189function add_passthrough_device() {
190    slot=$1
191    physical_bdf=$2
192    options=$3
193
194    unbind_device ${physical_bdf%,*}
195
196    # bus, device and function as decimal integers
197    bus_temp=${physical_bdf#*:};     bus=$((16#${bus_temp%:*}))
198    dev_temp=${physical_bdf##*:};    dev=$((16#${dev_temp%.*}))
199    fun=$((16#${physical_bdf#*.}))
200
201    echo -n "-s "
202    printf '%s,passthru,%x/%x/%x' ${slot} ${bus} ${dev} ${fun}
203    if [ -n "${options}" ]; then
204        echo -n ",${options}"
205    fi
206}
207