Jakob Vukalovic | 70ba633 | 2023-07-11 10:52:22 +0100 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | |
Jakob Vukalovic | 2d0cae5 | 2023-07-20 12:01:27 +0100 | [diff] [blame] | 3 | # Copyright 2023 Google Inc. All rights reserved. |
Jakob Vukalovic | 70ba633 | 2023-07-11 10:52:22 +0100 | [diff] [blame] | 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | |
| 17 | # prepare_device_vfio.sh: prepares a device for VFIO assignment by binding a VFIO driver to it |
| 18 | |
| 19 | adb="${ADB:="adb"}" # ADB command to use |
| 20 | vfio_dir="/dev/vfio" |
| 21 | platform_bus="/sys/bus/platform" |
| 22 | vfio_reset_required="/sys/module/vfio_platform/parameters/reset_required" |
| 23 | vfio_noiommu_param="/sys/module/vfio/parameters/enable_unsafe_noiommu_mode" |
| 24 | vfio_unsafe_interrupts_param="/sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts" |
| 25 | |
| 26 | function print_help() { |
| 27 | echo "prepare_device_vfio.sh prepares a device for VFIO assignment" |
| 28 | echo "" |
| 29 | echo " Usage:" |
| 30 | echo " $0 DEVICE_NAME" |
| 31 | echo " Prepare device DEVICE_NAME for VFIO assignment." |
| 32 | echo "" |
| 33 | echo " help - prints this help message" |
| 34 | } |
| 35 | |
| 36 | function cmd() { |
| 37 | $adb shell $@ |
| 38 | } |
| 39 | |
| 40 | function tcmd() { |
| 41 | trap "echo \"Error: adb shell command '$@' failed\" ; exit 1" ERR |
| 42 | $adb shell $@ |
| 43 | } |
| 44 | |
| 45 | function ensure_root() { |
| 46 | # Check user id |
| 47 | if [ $(cmd "id -u") != 0 ]; then |
| 48 | read -p "Must run as root; restart ADBD? [y/n] " answer |
| 49 | case $answer in |
| 50 | [Yy]* ) |
| 51 | $adb root && $adb wait-for-device && sleep 3 || exit 1 |
| 52 | ;; |
| 53 | * ) |
| 54 | exit 1 |
| 55 | esac |
| 56 | fi |
| 57 | } |
| 58 | |
| 59 | function check_vfio() { |
| 60 | cmd "[ -c $vfio_dir/vfio ]" |
| 61 | if [ $? -ne 0 ]; then |
| 62 | echo "cannot find $vfio_dir/vfio" |
| 63 | exit 1 |
| 64 | fi |
| 65 | |
| 66 | cmd "[ -d $platform_bus/drivers/vfio-platform ]" |
| 67 | if [ $? -ne 0 ]; then |
| 68 | echo "VFIO-platform is not supported" |
| 69 | exit 1 |
| 70 | fi |
| 71 | } |
| 72 | |
| 73 | function check_device() { |
| 74 | cmd "[ -d $device_sys ]" |
| 75 | if [ $? -ne 0 ]; then |
| 76 | echo "no device $device ($device_sys)" |
| 77 | exit 1 |
| 78 | fi |
| 79 | } |
| 80 | |
| 81 | function get_device_iommu_group() { |
| 82 | local group=$(cmd "basename \$(readlink \"$device_sys/iommu_group\")") |
| 83 | if [ $? -eq 0 ]; then |
| 84 | echo $group |
| 85 | else |
| 86 | echo "" |
| 87 | fi |
| 88 | } |
| 89 | |
| 90 | function misc_setup() { |
| 91 | # VFIO NOIOMMU check |
| 92 | if [ -z "$group" ]; then |
| 93 | echo "$device_sys does not have an IOMMU group - setting $vfio_noiommu_param" |
| 94 | tcmd "echo y > \"$vfio_noiommu_param\"" |
| 95 | fi |
| 96 | |
| 97 | # Disable SELinux to allow virtualizationmanager and crosvm to access sysfs |
| 98 | echo "[*WARN*] setenforce=0: SELinux is disabled" |
| 99 | tcmd "setenforce 0" |
| 100 | |
| 101 | # Samsung IOMMU does not report interrupt remapping support, so enable unsafe uinterrupts |
| 102 | if [ -n "$group" ]; then |
| 103 | local iommu_drv=$(cmd "basename \$(readlink \"$device_sys/iommu/device/driver\")") |
| 104 | if [ "$iommu_drv" = "samsung-sysmmu-v9" ]; then |
| 105 | tcmd "echo y > \"$vfio_unsafe_interrupts_param\"" |
| 106 | fi |
| 107 | fi |
| 108 | } |
| 109 | |
| 110 | function bind_vfio_driver() { |
| 111 | # Check if non-VFIO driver is currently bound, ie unbinding is needed |
| 112 | cmd "[ -e \"$device_driver\" ] && \ |
| 113 | [ ! \$(basename \$(readlink \"$device_driver\")) = \"vfio-platform\" ]" |
| 114 | if [ $? -eq 0 ]; then |
| 115 | # Unbind current driver |
| 116 | tcmd "echo \"$device\" > \"$device_driver/unbind\"" |
| 117 | fi |
| 118 | |
| 119 | # Bind to VFIO driver |
| 120 | cmd "[ ! -e \"$device_driver\" ]" |
| 121 | if [ $? -eq 0 ]; then |
| 122 | # Bind vfio-platform driver |
| 123 | tcmd "echo \"vfio-platform\" > \"$device_sys/driver_override\"" |
| 124 | tcmd "echo \"$device\" > \"$platform_bus/drivers_probe\"" |
| 125 | sleep 2 |
| 126 | fi |
| 127 | } |
| 128 | |
| 129 | function verify_vfio_driver() { |
| 130 | # Verify new VFIO file structure |
| 131 | group=$(get_device_iommu_group) |
| 132 | if [ -z "$group" ]; then |
| 133 | echo "cannot setup VFIO-NOIOMMU for $device_sys" |
| 134 | exit 1 |
| 135 | fi |
| 136 | |
| 137 | cmd "[ ! -c \"$vfio_dir/$group\" ] || \ |
| 138 | [ ! -e \"$device_driver\" ] || \ |
| 139 | [ ! \$(basename \$(readlink \"$device_driver\")) = \"vfio-platform\" ]" |
| 140 | if [ $? -eq 0 ]; then |
| 141 | echo "could not bind $device to VFIO platform driver" |
| 142 | |
| 143 | if [ $(cmd "cat $vfio_reset_required") = Y ]; then |
| 144 | echo "VFIO device reset handler must be registered. Either unset $vfio_reset_required, \ |
| 145 | or register a reset handler for $device_sys" |
| 146 | fi |
| 147 | exit 1 |
| 148 | fi |
| 149 | } |
| 150 | |
| 151 | function prepare_device() { |
| 152 | device="$1" |
| 153 | device_sys="/sys/bus/platform/devices/$device" |
| 154 | device_driver="$device_sys/driver" |
| 155 | |
| 156 | ensure_root |
| 157 | check_vfio |
| 158 | check_device |
| 159 | group=$(get_device_iommu_group) |
| 160 | misc_setup |
| 161 | |
| 162 | bind_vfio_driver |
| 163 | verify_vfio_driver |
| 164 | |
| 165 | echo "Device: $device_sys" |
| 166 | echo "IOMMU group: $group" |
| 167 | echo "VFIO group file: $vfio_dir/$group" |
| 168 | echo "Ready!" |
| 169 | } |
| 170 | |
| 171 | cmd=$1 |
| 172 | |
| 173 | case $cmd in |
| 174 | ""|help) print_help ;; |
| 175 | *) prepare_device "$cmd" $@ ;; |
| 176 | esac |