aboutsummaryrefslogtreecommitdiffstats
path: root/fdio.infra.ansible/roles/aws/files/get-vfio-with-wc.sh
blob: 02a3139b66480c9b86d48998e08969cb7a6746a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/usr/bin/env bash
# Enable WC in VFIO-PCI driver
# Tested on:
#  * Amazon Linux 2 AMI (HVM), SSD Volume Type - ami-0bb3fad3c0286ebd5
#  * Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type - ami-015232c01a82b847b
#  * Red Hat Enterprise Linux 8 (HVM), SSD Volume Type - ami-08f4717d06813bf00
#  * Ubuntu Server 20.04 LTS (HVM), SSD Volume Type - ami-06fd8a495a537da8b
#  * Ubuntu Server 18.04 LTS (HVM), SSD Volume Type - ami-0823c236601fef765

set -e

TMP_DIR="tmp"

# Kernel modules location:
P1="/usr/lib/modules/`uname -r`/kernel/drivers/vfio"
P2="/lib/modules/`uname -r`/kernel/drivers/vfio"

# This may return an error if executed from inside the script
set +e
RED="$(tput setaf 1)"
GREEN="$(tput setaf 2)"

BOLD="$(tput bold)"
NORMAL="$(tput sgr0)"
set -e

function bold {
	echo -e "${BOLD}${@}${NORMAL}"
}

function err {
	bold "${RED}ERROR: ${@}"
}

function green {
	bold "${GREEN}${@}"
}

function get_kernel_version {
	local ver=$(uname -r | cut -f 1 -d '-')
	local ver_major=$(echo $ver | cut -f1 -d '.')
	local ver_minor=$(echo $ver | cut -f2 -d '.')
	local ver_subminor=$(echo $ver | cut -f3 -d '.')

	printf "%d%02d%04d" "${ver_major}" "${ver_minor}" "${ver_subminor}"
}

function download_kernel_src_yum {
	echo "Use yum to get the kernel sources"

	bold "\nInstall required applications and kernel headers"
	yum install -y gcc "kernel-$(uname -r)" "kernel-devel-$(uname -r)" \
	    git make elfutils-libelf-devel patch yum-utils
	green Done

	# Download kernel source
	bold "\nDownload kernel source with vfio"
	yumdownloader --source "kernel-devel-$(uname -r)"
	rpm2cpio kernel*.src.rpm | cpio -idmv
	green Done

	rm -f *patches.tar
	tar xf linux-*.tar*
	rm -f linux-*.tar* linux-*.patch
}

function download_kernel_src_apt {
	echo "Use apt-get to get the kernel sources"
	apt-get -q -y update
	green Done

	bold "\nInstall required applications"
	apt-get -q -y install dpkg-dev build-essential git
	green Done

	bold "\nDownload Linux kernel source with vfio"
	if ! apt-get -q -y source -t focal linux-image-$(uname -r); then
		err "Cannot download Linux kernel source.\nPlease uncomment appropriate 'deb-src' line in the /etc/apt/sources.list file"
		exit 1
	fi
	green Done

	rm -f linux-*.dsc linux-*.gz
}

function download_kernel_src {
	bold "[1] Downloading prerequisites..."
	rm -rf "${TMP_DIR}"
	mkdir -p "${TMP_DIR}"
	cd "${TMP_DIR}"

	if apt-get -v >/dev/null 2>/dev/null; then
		download_kernel_src_apt
	else
		download_kernel_src_yum
	fi
	cd linux-*
}

function apply_wc_patch {
	echo "Using patch for kernel version 4.10"
	local wc_patch="${BASE_PATH}/patches/linux-4.10-vfio-wc.patch"

	if ! patch --ignore-whitespace -p1 < "${wc_patch}"; then
		err "Cannot apply patch: ${wc_patch}!"
		exit 1
	fi
}

function compile_vfio_driver {
	bold "\n[2] Patch and build the vfio driver"
	# Adjust VFIO-PCI driver

	bold "Apply patch for the write combining to the vfio-pci"
	apply_wc_patch
	green Done

	cd drivers/vfio
	# Configure Makefile - build VFIO with support for NOIOMMU mode
	bold "\nConfigure Makefile for standalone vfio build and noiommu mode support"
	echo "ccflags-y := -DCONFIG_VFIO_NOIOMMU=1" >> Makefile
	echo 'all:' >> Makefile
	echo '	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules' >> Makefile
	green Done

	bold "\nBuild the driver"
	if ! make; then
		err "Compilation error."
		exit 1
	fi
	green Done
}

function get_module_location {
	for p in ${P1} ${P2}; do
		if find "${p}" -name "vfio.*" >/dev/null 2>/dev/null; then
			MOD_PATH="${p}"
			break
		fi
	done

	if [ -z "${MOD_PATH}" ]; then
		err "Cannot find kernel modules location..."
		exit
	fi
}

function get_module_compression {
	if ls "${MOD_PATH}/vfio.ko.xz" >/dev/null 2>/dev/null; then
		XZ=".xz"
	else
		XZ=""
	fi
}

function replace_module {
	local installed=0

	bold "\n[3] Install module"
	get_module_location
	get_module_compression

	for name in "pci/vfio-pci.ko" "pci/vfio-pci-core.ko" "vfio.ko"; do
		if test -e "${MOD_PATH}/${name}${XZ}"; then
			if [ -n "${XZ}" ]; then
				xz "${name}" -c > "${name}${XZ}"
			fi
			mv "${MOD_PATH}/${name}${XZ}" "${MOD_PATH}/${name}${XZ}_no_wc"
			cp "${name}${XZ}" "${MOD_PATH}/${name}${XZ}"
			bold "Installing: ${MOD_PATH}/${name}${XZ}"
			installed=1
		fi
	done
	if [ "${installed}" -eq 1 ]; then
		green "Module installed at: ${MOD_PATH}"
	else
		err "Failure during vfio-pci module installation. Prehaps it's not provided as a kernel module!"
		exit 1
	fi
}

###############################################
# Main script code
###############################################

if [ "$(id -u)" -ne 0 ]; then
	err 'Please execute script as a root'
	exit 1
fi

cd $(dirname ${0})
BASE_PATH=$(pwd)

KERNEL_VERSION=$(get_kernel_version)

if [ "${KERNEL_VERSION}" -lt 4100000 ]; then
	err "Kernel version: $(uname -r) is not supported by the script. Please upgrade kernel to at least v4.10."
	exit 1
fi

download_kernel_src
compile_vfio_driver
replace_module