xref: /linux/scripts/livepatch/klp-build (revision 24ebfcd65a871df4555b98c49c9ed9a92f146113)
1*24ebfcd6SJosh Poimboeuf#!/bin/bash
2*24ebfcd6SJosh Poimboeuf# SPDX-License-Identifier: GPL-2.0
3*24ebfcd6SJosh Poimboeuf#
4*24ebfcd6SJosh Poimboeuf# Build a livepatch module
5*24ebfcd6SJosh Poimboeuf
6*24ebfcd6SJosh Poimboeuf# shellcheck disable=SC1090,SC2155
7*24ebfcd6SJosh Poimboeuf
8*24ebfcd6SJosh Poimboeufif (( BASH_VERSINFO[0]  < 4 || \
9*24ebfcd6SJosh Poimboeuf     (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 4) )); then
10*24ebfcd6SJosh Poimboeuf		echo "error: this script requires bash 4.4+" >&2
11*24ebfcd6SJosh Poimboeuf	exit 1
12*24ebfcd6SJosh Poimboeuffi
13*24ebfcd6SJosh Poimboeuf
14*24ebfcd6SJosh Poimboeufset -o errexit
15*24ebfcd6SJosh Poimboeufset -o errtrace
16*24ebfcd6SJosh Poimboeufset -o pipefail
17*24ebfcd6SJosh Poimboeufset -o nounset
18*24ebfcd6SJosh Poimboeuf
19*24ebfcd6SJosh Poimboeuf# Allow doing 'cmd | mapfile -t array' instead of 'mapfile -t array < <(cmd)'.
20*24ebfcd6SJosh Poimboeuf# This helps keep execution in pipes so pipefail+errexit can catch errors.
21*24ebfcd6SJosh Poimboeufshopt -s lastpipe
22*24ebfcd6SJosh Poimboeuf
23*24ebfcd6SJosh Poimboeufunset SKIP_CLEANUP XTRACE
24*24ebfcd6SJosh Poimboeuf
25*24ebfcd6SJosh PoimboeufREPLACE=1
26*24ebfcd6SJosh PoimboeufSHORT_CIRCUIT=0
27*24ebfcd6SJosh PoimboeufJOBS="$(getconf _NPROCESSORS_ONLN)"
28*24ebfcd6SJosh PoimboeufVERBOSE="-s"
29*24ebfcd6SJosh Poimboeufshopt -o xtrace | grep -q 'on' && XTRACE=1
30*24ebfcd6SJosh Poimboeuf
31*24ebfcd6SJosh Poimboeuf# Avoid removing the previous $TMP_DIR until args have been fully processed.
32*24ebfcd6SJosh PoimboeufKEEP_TMP=1
33*24ebfcd6SJosh Poimboeuf
34*24ebfcd6SJosh PoimboeufSCRIPT="$(basename "$0")"
35*24ebfcd6SJosh PoimboeufSCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36*24ebfcd6SJosh PoimboeufFIX_PATCH_LINES="$SCRIPT_DIR/fix-patch-lines"
37*24ebfcd6SJosh Poimboeuf
38*24ebfcd6SJosh PoimboeufSRC="$(pwd)"
39*24ebfcd6SJosh PoimboeufOBJ="$(pwd)"
40*24ebfcd6SJosh Poimboeuf
41*24ebfcd6SJosh PoimboeufCONFIG="$OBJ/.config"
42*24ebfcd6SJosh PoimboeufTMP_DIR="$OBJ/klp-tmp"
43*24ebfcd6SJosh Poimboeuf
44*24ebfcd6SJosh PoimboeufORIG_DIR="$TMP_DIR/orig"
45*24ebfcd6SJosh PoimboeufPATCHED_DIR="$TMP_DIR/patched"
46*24ebfcd6SJosh PoimboeufDIFF_DIR="$TMP_DIR/diff"
47*24ebfcd6SJosh PoimboeufKMOD_DIR="$TMP_DIR/kmod"
48*24ebfcd6SJosh Poimboeuf
49*24ebfcd6SJosh PoimboeufSTASH_DIR="$TMP_DIR/stash"
50*24ebfcd6SJosh PoimboeufTIMESTAMP="$TMP_DIR/timestamp"
51*24ebfcd6SJosh PoimboeufPATCH_TMP_DIR="$TMP_DIR/tmp"
52*24ebfcd6SJosh Poimboeuf
53*24ebfcd6SJosh PoimboeufKLP_DIFF_LOG="$DIFF_DIR/diff.log"
54*24ebfcd6SJosh Poimboeuf
55*24ebfcd6SJosh Poimboeufgrep0() {
56*24ebfcd6SJosh Poimboeuf	command grep "$@" || true
57*24ebfcd6SJosh Poimboeuf}
58*24ebfcd6SJosh Poimboeuf
59*24ebfcd6SJosh Poimboeufstatus() {
60*24ebfcd6SJosh Poimboeuf	echo "$*"
61*24ebfcd6SJosh Poimboeuf}
62*24ebfcd6SJosh Poimboeuf
63*24ebfcd6SJosh Poimboeufwarn() {
64*24ebfcd6SJosh Poimboeuf	echo "error: $SCRIPT: $*" >&2
65*24ebfcd6SJosh Poimboeuf}
66*24ebfcd6SJosh Poimboeuf
67*24ebfcd6SJosh Poimboeufdie() {
68*24ebfcd6SJosh Poimboeuf	warn "$@"
69*24ebfcd6SJosh Poimboeuf	exit 1
70*24ebfcd6SJosh Poimboeuf}
71*24ebfcd6SJosh Poimboeuf
72*24ebfcd6SJosh Poimboeufdeclare -a STASHED_FILES
73*24ebfcd6SJosh Poimboeuf
74*24ebfcd6SJosh Poimboeufstash_file() {
75*24ebfcd6SJosh Poimboeuf	local file="$1"
76*24ebfcd6SJosh Poimboeuf	local rel_file="${file#"$SRC"/}"
77*24ebfcd6SJosh Poimboeuf
78*24ebfcd6SJosh Poimboeuf	[[ ! -e "$file" ]] && die "no file to stash: $file"
79*24ebfcd6SJosh Poimboeuf
80*24ebfcd6SJosh Poimboeuf	mkdir -p "$STASH_DIR/$(dirname "$rel_file")"
81*24ebfcd6SJosh Poimboeuf	cp -f "$file" "$STASH_DIR/$rel_file"
82*24ebfcd6SJosh Poimboeuf
83*24ebfcd6SJosh Poimboeuf	STASHED_FILES+=("$rel_file")
84*24ebfcd6SJosh Poimboeuf}
85*24ebfcd6SJosh Poimboeuf
86*24ebfcd6SJosh Poimboeufrestore_files() {
87*24ebfcd6SJosh Poimboeuf	local file
88*24ebfcd6SJosh Poimboeuf
89*24ebfcd6SJosh Poimboeuf	for file in "${STASHED_FILES[@]}"; do
90*24ebfcd6SJosh Poimboeuf		mv -f "$STASH_DIR/$file" "$SRC/$file" || warn "can't restore file: $file"
91*24ebfcd6SJosh Poimboeuf	done
92*24ebfcd6SJosh Poimboeuf
93*24ebfcd6SJosh Poimboeuf	STASHED_FILES=()
94*24ebfcd6SJosh Poimboeuf}
95*24ebfcd6SJosh Poimboeuf
96*24ebfcd6SJosh Poimboeufcleanup() {
97*24ebfcd6SJosh Poimboeuf	set +o nounset
98*24ebfcd6SJosh Poimboeuf	revert_patches "--recount"
99*24ebfcd6SJosh Poimboeuf	restore_files
100*24ebfcd6SJosh Poimboeuf	[[ "$KEEP_TMP" -eq 0 ]] && rm -rf "$TMP_DIR"
101*24ebfcd6SJosh Poimboeuf	return 0
102*24ebfcd6SJosh Poimboeuf}
103*24ebfcd6SJosh Poimboeuf
104*24ebfcd6SJosh Poimboeuftrap_err() {
105*24ebfcd6SJosh Poimboeuf	warn "line ${BASH_LINENO[0]}: '$BASH_COMMAND'"
106*24ebfcd6SJosh Poimboeuf}
107*24ebfcd6SJosh Poimboeuf
108*24ebfcd6SJosh Poimboeuftrap cleanup  EXIT INT TERM HUP
109*24ebfcd6SJosh Poimboeuftrap trap_err ERR
110*24ebfcd6SJosh Poimboeuf
111*24ebfcd6SJosh Poimboeuf__usage() {
112*24ebfcd6SJosh Poimboeuf	cat <<EOF
113*24ebfcd6SJosh PoimboeufUsage: $SCRIPT [OPTIONS] PATCH_FILE(s)
114*24ebfcd6SJosh PoimboeufGenerate a livepatch module.
115*24ebfcd6SJosh Poimboeuf
116*24ebfcd6SJosh PoimboeufOptions:
117*24ebfcd6SJosh Poimboeuf   -j, --jobs=<jobs>		Build jobs to run simultaneously [default: $JOBS]
118*24ebfcd6SJosh Poimboeuf   -o, --output=<file.ko>	Output file [default: livepatch-<patch-name>.ko]
119*24ebfcd6SJosh Poimboeuf       --no-replace		Disable livepatch atomic replace
120*24ebfcd6SJosh Poimboeuf   -v, --verbose		Pass V=1 to kernel/module builds
121*24ebfcd6SJosh Poimboeuf
122*24ebfcd6SJosh PoimboeufAdvanced Options:
123*24ebfcd6SJosh Poimboeuf   -S, --short-circuit=STEP	Start at build step (requires prior --keep-tmp)
124*24ebfcd6SJosh Poimboeuf				   1|orig	Build original kernel (default)
125*24ebfcd6SJosh Poimboeuf				   2|patched	Build patched kernel
126*24ebfcd6SJosh Poimboeuf				   3|diff	Diff objects
127*24ebfcd6SJosh Poimboeuf				   4|kmod	Build patch module
128*24ebfcd6SJosh Poimboeuf   -T, --keep-tmp		Preserve tmp dir on exit
129*24ebfcd6SJosh Poimboeuf
130*24ebfcd6SJosh PoimboeufEOF
131*24ebfcd6SJosh Poimboeuf}
132*24ebfcd6SJosh Poimboeuf
133*24ebfcd6SJosh Poimboeufusage() {
134*24ebfcd6SJosh Poimboeuf	__usage >&2
135*24ebfcd6SJosh Poimboeuf}
136*24ebfcd6SJosh Poimboeuf
137*24ebfcd6SJosh Poimboeufprocess_args() {
138*24ebfcd6SJosh Poimboeuf	local keep_tmp=0
139*24ebfcd6SJosh Poimboeuf	local short
140*24ebfcd6SJosh Poimboeuf	local long
141*24ebfcd6SJosh Poimboeuf	local args
142*24ebfcd6SJosh Poimboeuf
143*24ebfcd6SJosh Poimboeuf	short="hj:o:vS:T"
144*24ebfcd6SJosh Poimboeuf	long="help,jobs:,output:,no-replace,verbose,short-circuit:,keep-tmp"
145*24ebfcd6SJosh Poimboeuf
146*24ebfcd6SJosh Poimboeuf	args=$(getopt --options "$short" --longoptions "$long" -- "$@") || {
147*24ebfcd6SJosh Poimboeuf		echo; usage; exit
148*24ebfcd6SJosh Poimboeuf	}
149*24ebfcd6SJosh Poimboeuf	eval set -- "$args"
150*24ebfcd6SJosh Poimboeuf
151*24ebfcd6SJosh Poimboeuf	while true; do
152*24ebfcd6SJosh Poimboeuf		case "$1" in
153*24ebfcd6SJosh Poimboeuf			-h | --help)
154*24ebfcd6SJosh Poimboeuf				usage
155*24ebfcd6SJosh Poimboeuf				exit 0
156*24ebfcd6SJosh Poimboeuf				;;
157*24ebfcd6SJosh Poimboeuf			-j | --jobs)
158*24ebfcd6SJosh Poimboeuf				JOBS="$2"
159*24ebfcd6SJosh Poimboeuf				shift 2
160*24ebfcd6SJosh Poimboeuf				;;
161*24ebfcd6SJosh Poimboeuf			-o | --output)
162*24ebfcd6SJosh Poimboeuf				[[ "$2" != *.ko ]] && die "output filename should end with .ko"
163*24ebfcd6SJosh Poimboeuf				OUTFILE="$2"
164*24ebfcd6SJosh Poimboeuf				NAME="$(basename "$OUTFILE")"
165*24ebfcd6SJosh Poimboeuf				NAME="${NAME%.ko}"
166*24ebfcd6SJosh Poimboeuf				NAME="$(module_name_string "$NAME")"
167*24ebfcd6SJosh Poimboeuf				shift 2
168*24ebfcd6SJosh Poimboeuf				;;
169*24ebfcd6SJosh Poimboeuf			--no-replace)
170*24ebfcd6SJosh Poimboeuf				REPLACE=0
171*24ebfcd6SJosh Poimboeuf				shift
172*24ebfcd6SJosh Poimboeuf				;;
173*24ebfcd6SJosh Poimboeuf			-v | --verbose)
174*24ebfcd6SJosh Poimboeuf				VERBOSE="V=1"
175*24ebfcd6SJosh Poimboeuf				shift
176*24ebfcd6SJosh Poimboeuf				;;
177*24ebfcd6SJosh Poimboeuf			-S | --short-circuit)
178*24ebfcd6SJosh Poimboeuf				[[ ! -d "$TMP_DIR" ]] && die "--short-circuit requires preserved klp-tmp dir"
179*24ebfcd6SJosh Poimboeuf				keep_tmp=1
180*24ebfcd6SJosh Poimboeuf				case "$2" in
181*24ebfcd6SJosh Poimboeuf					1 | orig)	SHORT_CIRCUIT=1; ;;
182*24ebfcd6SJosh Poimboeuf					2 | patched)	SHORT_CIRCUIT=2; ;;
183*24ebfcd6SJosh Poimboeuf					3 | diff)	SHORT_CIRCUIT=3; ;;
184*24ebfcd6SJosh Poimboeuf					4 | mod)	SHORT_CIRCUIT=4; ;;
185*24ebfcd6SJosh Poimboeuf					*)		die "invalid short-circuit step '$2'" ;;
186*24ebfcd6SJosh Poimboeuf				esac
187*24ebfcd6SJosh Poimboeuf				shift 2
188*24ebfcd6SJosh Poimboeuf				;;
189*24ebfcd6SJosh Poimboeuf			-T | --keep-tmp)
190*24ebfcd6SJosh Poimboeuf				keep_tmp=1
191*24ebfcd6SJosh Poimboeuf				shift
192*24ebfcd6SJosh Poimboeuf				;;
193*24ebfcd6SJosh Poimboeuf			--)
194*24ebfcd6SJosh Poimboeuf				shift
195*24ebfcd6SJosh Poimboeuf				break
196*24ebfcd6SJosh Poimboeuf				;;
197*24ebfcd6SJosh Poimboeuf			*)
198*24ebfcd6SJosh Poimboeuf				usage
199*24ebfcd6SJosh Poimboeuf				exit 1
200*24ebfcd6SJosh Poimboeuf				;;
201*24ebfcd6SJosh Poimboeuf		esac
202*24ebfcd6SJosh Poimboeuf	done
203*24ebfcd6SJosh Poimboeuf
204*24ebfcd6SJosh Poimboeuf	if [[ $# -eq 0 ]]; then
205*24ebfcd6SJosh Poimboeuf		usage
206*24ebfcd6SJosh Poimboeuf		exit 1
207*24ebfcd6SJosh Poimboeuf	fi
208*24ebfcd6SJosh Poimboeuf
209*24ebfcd6SJosh Poimboeuf	KEEP_TMP="$keep_tmp"
210*24ebfcd6SJosh Poimboeuf	PATCHES=("$@")
211*24ebfcd6SJosh Poimboeuf}
212*24ebfcd6SJosh Poimboeuf
213*24ebfcd6SJosh Poimboeuf# temporarily disable xtrace for especially verbose code
214*24ebfcd6SJosh Poimboeufxtrace_save() {
215*24ebfcd6SJosh Poimboeuf	[[ -v XTRACE ]] && set +x
216*24ebfcd6SJosh Poimboeuf	return 0
217*24ebfcd6SJosh Poimboeuf}
218*24ebfcd6SJosh Poimboeuf
219*24ebfcd6SJosh Poimboeufxtrace_restore() {
220*24ebfcd6SJosh Poimboeuf	[[ -v XTRACE ]] && set -x
221*24ebfcd6SJosh Poimboeuf	return 0
222*24ebfcd6SJosh Poimboeuf}
223*24ebfcd6SJosh Poimboeuf
224*24ebfcd6SJosh Poimboeufvalidate_config() {
225*24ebfcd6SJosh Poimboeuf	xtrace_save "reading .config"
226*24ebfcd6SJosh Poimboeuf	source "$CONFIG" || die "no .config file in $(dirname "$CONFIG")"
227*24ebfcd6SJosh Poimboeuf	xtrace_restore
228*24ebfcd6SJosh Poimboeuf
229*24ebfcd6SJosh Poimboeuf	[[ -v CONFIG_LIVEPATCH ]] ||			\
230*24ebfcd6SJosh Poimboeuf		die "CONFIG_LIVEPATCH not enabled"
231*24ebfcd6SJosh Poimboeuf
232*24ebfcd6SJosh Poimboeuf	[[ -v CONFIG_KLP_BUILD ]] ||			\
233*24ebfcd6SJosh Poimboeuf		die "CONFIG_KLP_BUILD not enabled"
234*24ebfcd6SJosh Poimboeuf
235*24ebfcd6SJosh Poimboeuf	[[ -v CONFIG_GCC_PLUGIN_LATENT_ENTROPY ]] &&	\
236*24ebfcd6SJosh Poimboeuf		die "kernel option 'CONFIG_GCC_PLUGIN_LATENT_ENTROPY' not supported"
237*24ebfcd6SJosh Poimboeuf
238*24ebfcd6SJosh Poimboeuf	[[ -v CONFIG_GCC_PLUGIN_RANDSTRUCT ]] &&	\
239*24ebfcd6SJosh Poimboeuf		die "kernel option 'CONFIG_GCC_PLUGIN_RANDSTRUCT' not supported"
240*24ebfcd6SJosh Poimboeuf
241*24ebfcd6SJosh Poimboeuf	return 0
242*24ebfcd6SJosh Poimboeuf}
243*24ebfcd6SJosh Poimboeuf
244*24ebfcd6SJosh Poimboeuf# Only allow alphanumerics and '_' and '-' in the module name.  Everything else
245*24ebfcd6SJosh Poimboeuf# is replaced with '-'.  Also truncate to 55 chars so the full name + NUL
246*24ebfcd6SJosh Poimboeuf# terminator fits in the kernel's 56-byte module name array.
247*24ebfcd6SJosh Poimboeufmodule_name_string() {
248*24ebfcd6SJosh Poimboeuf	echo "${1//[^a-zA-Z0-9_-]/-}" | cut -c 1-55
249*24ebfcd6SJosh Poimboeuf}
250*24ebfcd6SJosh Poimboeuf
251*24ebfcd6SJosh Poimboeuf# If the module name wasn't specified on the cmdline with --output, give it a
252*24ebfcd6SJosh Poimboeuf# name based on the patch name.
253*24ebfcd6SJosh Poimboeufset_module_name() {
254*24ebfcd6SJosh Poimboeuf	[[ -v NAME ]] && return 0
255*24ebfcd6SJosh Poimboeuf
256*24ebfcd6SJosh Poimboeuf	if [[ "${#PATCHES[@]}" -eq 1 ]]; then
257*24ebfcd6SJosh Poimboeuf		NAME="$(basename "${PATCHES[0]}")"
258*24ebfcd6SJosh Poimboeuf		NAME="${NAME%.*}"
259*24ebfcd6SJosh Poimboeuf	else
260*24ebfcd6SJosh Poimboeuf		NAME="patch"
261*24ebfcd6SJosh Poimboeuf	fi
262*24ebfcd6SJosh Poimboeuf
263*24ebfcd6SJosh Poimboeuf	NAME="livepatch-$NAME"
264*24ebfcd6SJosh Poimboeuf	NAME="$(module_name_string "$NAME")"
265*24ebfcd6SJosh Poimboeuf
266*24ebfcd6SJosh Poimboeuf	OUTFILE="$NAME.ko"
267*24ebfcd6SJosh Poimboeuf}
268*24ebfcd6SJosh Poimboeuf
269*24ebfcd6SJosh Poimboeuf# Hardcode the value printed by the localversion script to prevent patch
270*24ebfcd6SJosh Poimboeuf# application from appending it with '+' due to a dirty git working tree.
271*24ebfcd6SJosh Poimboeufset_kernelversion() {
272*24ebfcd6SJosh Poimboeuf	local file="$SRC/scripts/setlocalversion"
273*24ebfcd6SJosh Poimboeuf	local localversion
274*24ebfcd6SJosh Poimboeuf
275*24ebfcd6SJosh Poimboeuf	stash_file "$file"
276*24ebfcd6SJosh Poimboeuf
277*24ebfcd6SJosh Poimboeuf	localversion="$(cd "$SRC" && make --no-print-directory kernelversion)"
278*24ebfcd6SJosh Poimboeuf	localversion="$(cd "$SRC" && KERNELVERSION="$localversion" ./scripts/setlocalversion)"
279*24ebfcd6SJosh Poimboeuf	[[ -z "$localversion" ]] && die "setlocalversion failed"
280*24ebfcd6SJosh Poimboeuf
281*24ebfcd6SJosh Poimboeuf	sed -i "2i echo $localversion; exit 0" scripts/setlocalversion
282*24ebfcd6SJosh Poimboeuf}
283*24ebfcd6SJosh Poimboeuf
284*24ebfcd6SJosh Poimboeufget_patch_files() {
285*24ebfcd6SJosh Poimboeuf	local patch="$1"
286*24ebfcd6SJosh Poimboeuf
287*24ebfcd6SJosh Poimboeuf	grep0 -E '^(--- |\+\+\+ )' "$patch"			\
288*24ebfcd6SJosh Poimboeuf		| gawk '{print $2}'				\
289*24ebfcd6SJosh Poimboeuf		| sed 's|^[^/]*/||'				\
290*24ebfcd6SJosh Poimboeuf		| sort -u
291*24ebfcd6SJosh Poimboeuf}
292*24ebfcd6SJosh Poimboeuf
293*24ebfcd6SJosh Poimboeuf# Make sure git re-stats the changed files
294*24ebfcd6SJosh Poimboeufgit_refresh() {
295*24ebfcd6SJosh Poimboeuf	local patch="$1"
296*24ebfcd6SJosh Poimboeuf	local files=()
297*24ebfcd6SJosh Poimboeuf
298*24ebfcd6SJosh Poimboeuf	[[ ! -e "$SRC/.git" ]] && return
299*24ebfcd6SJosh Poimboeuf
300*24ebfcd6SJosh Poimboeuf	get_patch_files "$patch" | mapfile -t files
301*24ebfcd6SJosh Poimboeuf
302*24ebfcd6SJosh Poimboeuf	(
303*24ebfcd6SJosh Poimboeuf		cd "$SRC"
304*24ebfcd6SJosh Poimboeuf		git update-index -q --refresh -- "${files[@]}"
305*24ebfcd6SJosh Poimboeuf	)
306*24ebfcd6SJosh Poimboeuf}
307*24ebfcd6SJosh Poimboeuf
308*24ebfcd6SJosh Poimboeufcheck_unsupported_patches() {
309*24ebfcd6SJosh Poimboeuf	local patch
310*24ebfcd6SJosh Poimboeuf
311*24ebfcd6SJosh Poimboeuf	for patch in "${PATCHES[@]}"; do
312*24ebfcd6SJosh Poimboeuf		local files=()
313*24ebfcd6SJosh Poimboeuf
314*24ebfcd6SJosh Poimboeuf		get_patch_files "$patch" | mapfile -t files
315*24ebfcd6SJosh Poimboeuf
316*24ebfcd6SJosh Poimboeuf		for file in "${files[@]}"; do
317*24ebfcd6SJosh Poimboeuf			case "$file" in
318*24ebfcd6SJosh Poimboeuf				lib/*|*.S)
319*24ebfcd6SJosh Poimboeuf					die "unsupported patch to $file"
320*24ebfcd6SJosh Poimboeuf					;;
321*24ebfcd6SJosh Poimboeuf			esac
322*24ebfcd6SJosh Poimboeuf		done
323*24ebfcd6SJosh Poimboeuf	done
324*24ebfcd6SJosh Poimboeuf}
325*24ebfcd6SJosh Poimboeuf
326*24ebfcd6SJosh Poimboeufapply_patch() {
327*24ebfcd6SJosh Poimboeuf	local patch="$1"
328*24ebfcd6SJosh Poimboeuf	shift
329*24ebfcd6SJosh Poimboeuf	local extra_args=("$@")
330*24ebfcd6SJosh Poimboeuf
331*24ebfcd6SJosh Poimboeuf	[[ ! -f "$patch" ]] && die "$patch doesn't exist"
332*24ebfcd6SJosh Poimboeuf
333*24ebfcd6SJosh Poimboeuf	(
334*24ebfcd6SJosh Poimboeuf		cd "$SRC"
335*24ebfcd6SJosh Poimboeuf
336*24ebfcd6SJosh Poimboeuf		# The sed strips the version signature from 'git format-patch',
337*24ebfcd6SJosh Poimboeuf		# otherwise 'git apply --recount' warns.
338*24ebfcd6SJosh Poimboeuf		sed -n '/^-- /q;p' "$patch" |
339*24ebfcd6SJosh Poimboeuf			git apply "${extra_args[@]}"
340*24ebfcd6SJosh Poimboeuf	)
341*24ebfcd6SJosh Poimboeuf
342*24ebfcd6SJosh Poimboeuf	APPLIED_PATCHES+=("$patch")
343*24ebfcd6SJosh Poimboeuf}
344*24ebfcd6SJosh Poimboeuf
345*24ebfcd6SJosh Poimboeufrevert_patch() {
346*24ebfcd6SJosh Poimboeuf	local patch="$1"
347*24ebfcd6SJosh Poimboeuf	shift
348*24ebfcd6SJosh Poimboeuf	local extra_args=("$@")
349*24ebfcd6SJosh Poimboeuf	local tmp=()
350*24ebfcd6SJosh Poimboeuf
351*24ebfcd6SJosh Poimboeuf	(
352*24ebfcd6SJosh Poimboeuf		cd "$SRC"
353*24ebfcd6SJosh Poimboeuf
354*24ebfcd6SJosh Poimboeuf		sed -n '/^-- /q;p' "$patch" |
355*24ebfcd6SJosh Poimboeuf			git apply --reverse "${extra_args[@]}"
356*24ebfcd6SJosh Poimboeuf	)
357*24ebfcd6SJosh Poimboeuf	git_refresh "$patch"
358*24ebfcd6SJosh Poimboeuf
359*24ebfcd6SJosh Poimboeuf	for p in "${APPLIED_PATCHES[@]}"; do
360*24ebfcd6SJosh Poimboeuf		[[ "$p" == "$patch" ]] && continue
361*24ebfcd6SJosh Poimboeuf		tmp+=("$p")
362*24ebfcd6SJosh Poimboeuf	done
363*24ebfcd6SJosh Poimboeuf
364*24ebfcd6SJosh Poimboeuf	APPLIED_PATCHES=("${tmp[@]}")
365*24ebfcd6SJosh Poimboeuf}
366*24ebfcd6SJosh Poimboeuf
367*24ebfcd6SJosh Poimboeufapply_patches() {
368*24ebfcd6SJosh Poimboeuf	local patch
369*24ebfcd6SJosh Poimboeuf
370*24ebfcd6SJosh Poimboeuf	for patch in "${PATCHES[@]}"; do
371*24ebfcd6SJosh Poimboeuf		apply_patch "$patch"
372*24ebfcd6SJosh Poimboeuf	done
373*24ebfcd6SJosh Poimboeuf}
374*24ebfcd6SJosh Poimboeuf
375*24ebfcd6SJosh Poimboeufrevert_patches() {
376*24ebfcd6SJosh Poimboeuf	local extra_args=("$@")
377*24ebfcd6SJosh Poimboeuf	local patches=("${APPLIED_PATCHES[@]}")
378*24ebfcd6SJosh Poimboeuf
379*24ebfcd6SJosh Poimboeuf	for (( i=${#patches[@]}-1 ; i>=0 ; i-- )) ; do
380*24ebfcd6SJosh Poimboeuf		revert_patch "${patches[$i]}" "${extra_args[@]}"
381*24ebfcd6SJosh Poimboeuf	done
382*24ebfcd6SJosh Poimboeuf
383*24ebfcd6SJosh Poimboeuf	APPLIED_PATCHES=()
384*24ebfcd6SJosh Poimboeuf}
385*24ebfcd6SJosh Poimboeuf
386*24ebfcd6SJosh Poimboeufvalidate_patches() {
387*24ebfcd6SJosh Poimboeuf	check_unsupported_patches
388*24ebfcd6SJosh Poimboeuf	apply_patches
389*24ebfcd6SJosh Poimboeuf	revert_patches
390*24ebfcd6SJosh Poimboeuf}
391*24ebfcd6SJosh Poimboeuf
392*24ebfcd6SJosh Poimboeufdo_init() {
393*24ebfcd6SJosh Poimboeuf	# We're not yet smart enough to handle anything other than in-tree
394*24ebfcd6SJosh Poimboeuf	# builds in pwd.
395*24ebfcd6SJosh Poimboeuf	[[ ! "$SRC" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
396*24ebfcd6SJosh Poimboeuf	[[ ! "$OBJ" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
397*24ebfcd6SJosh Poimboeuf
398*24ebfcd6SJosh Poimboeuf	(( SHORT_CIRCUIT <= 1 )) && rm -rf "$TMP_DIR"
399*24ebfcd6SJosh Poimboeuf	mkdir -p "$TMP_DIR"
400*24ebfcd6SJosh Poimboeuf
401*24ebfcd6SJosh Poimboeuf	APPLIED_PATCHES=()
402*24ebfcd6SJosh Poimboeuf
403*24ebfcd6SJosh Poimboeuf	[[ -x "$FIX_PATCH_LINES" ]] || die "can't find fix-patch-lines"
404*24ebfcd6SJosh Poimboeuf
405*24ebfcd6SJosh Poimboeuf	validate_config
406*24ebfcd6SJosh Poimboeuf	set_module_name
407*24ebfcd6SJosh Poimboeuf	set_kernelversion
408*24ebfcd6SJosh Poimboeuf}
409*24ebfcd6SJosh Poimboeuf
410*24ebfcd6SJosh Poimboeuf# Refresh the patch hunk headers, specifically the line numbers and counts.
411*24ebfcd6SJosh Poimboeufrefresh_patch() {
412*24ebfcd6SJosh Poimboeuf	local patch="$1"
413*24ebfcd6SJosh Poimboeuf	local tmpdir="$PATCH_TMP_DIR"
414*24ebfcd6SJosh Poimboeuf	local files=()
415*24ebfcd6SJosh Poimboeuf
416*24ebfcd6SJosh Poimboeuf	rm -rf "$tmpdir"
417*24ebfcd6SJosh Poimboeuf	mkdir -p "$tmpdir/a"
418*24ebfcd6SJosh Poimboeuf	mkdir -p "$tmpdir/b"
419*24ebfcd6SJosh Poimboeuf
420*24ebfcd6SJosh Poimboeuf	# Get all source files affected by the patch
421*24ebfcd6SJosh Poimboeuf	get_patch_files "$patch" | mapfile -t files
422*24ebfcd6SJosh Poimboeuf
423*24ebfcd6SJosh Poimboeuf	# Copy orig source files to 'a'
424*24ebfcd6SJosh Poimboeuf	( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/a" )
425*24ebfcd6SJosh Poimboeuf
426*24ebfcd6SJosh Poimboeuf	# Copy patched source files to 'b'
427*24ebfcd6SJosh Poimboeuf	apply_patch "$patch" --recount
428*24ebfcd6SJosh Poimboeuf	( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/b" )
429*24ebfcd6SJosh Poimboeuf	revert_patch "$patch" --recount
430*24ebfcd6SJosh Poimboeuf
431*24ebfcd6SJosh Poimboeuf	# Diff 'a' and 'b' to make a clean patch
432*24ebfcd6SJosh Poimboeuf	( cd "$tmpdir" && git diff --no-index --no-prefix a b > "$patch" ) || true
433*24ebfcd6SJosh Poimboeuf}
434*24ebfcd6SJosh Poimboeuf
435*24ebfcd6SJosh Poimboeuf# Copy the patches to a temporary directory, fix their lines so as not to
436*24ebfcd6SJosh Poimboeuf# affect the __LINE__ macro for otherwise unchanged functions further down the
437*24ebfcd6SJosh Poimboeuf# file, and update $PATCHES to point to the fixed patches.
438*24ebfcd6SJosh Poimboeuffix_patches() {
439*24ebfcd6SJosh Poimboeuf	local idx
440*24ebfcd6SJosh Poimboeuf	local i
441*24ebfcd6SJosh Poimboeuf
442*24ebfcd6SJosh Poimboeuf	rm -f "$TMP_DIR"/*.patch
443*24ebfcd6SJosh Poimboeuf
444*24ebfcd6SJosh Poimboeuf	idx=0001
445*24ebfcd6SJosh Poimboeuf	for i in "${!PATCHES[@]}"; do
446*24ebfcd6SJosh Poimboeuf		local old_patch="${PATCHES[$i]}"
447*24ebfcd6SJosh Poimboeuf		local tmp_patch="$TMP_DIR/tmp.patch"
448*24ebfcd6SJosh Poimboeuf		local patch="${PATCHES[$i]}"
449*24ebfcd6SJosh Poimboeuf		local new_patch
450*24ebfcd6SJosh Poimboeuf
451*24ebfcd6SJosh Poimboeuf		new_patch="$TMP_DIR/$idx-fixed-$(basename "$patch")"
452*24ebfcd6SJosh Poimboeuf
453*24ebfcd6SJosh Poimboeuf		cp -f "$old_patch" "$tmp_patch"
454*24ebfcd6SJosh Poimboeuf		refresh_patch "$tmp_patch"
455*24ebfcd6SJosh Poimboeuf		"$FIX_PATCH_LINES" "$tmp_patch" > "$new_patch"
456*24ebfcd6SJosh Poimboeuf		refresh_patch "$new_patch"
457*24ebfcd6SJosh Poimboeuf
458*24ebfcd6SJosh Poimboeuf		PATCHES[i]="$new_patch"
459*24ebfcd6SJosh Poimboeuf
460*24ebfcd6SJosh Poimboeuf		rm -f "$tmp_patch"
461*24ebfcd6SJosh Poimboeuf		idx=$(printf "%04d" $(( 10#$idx + 1 )))
462*24ebfcd6SJosh Poimboeuf	done
463*24ebfcd6SJosh Poimboeuf}
464*24ebfcd6SJosh Poimboeuf
465*24ebfcd6SJosh Poimboeufclean_kernel() {
466*24ebfcd6SJosh Poimboeuf	local cmd=()
467*24ebfcd6SJosh Poimboeuf
468*24ebfcd6SJosh Poimboeuf	cmd=("make")
469*24ebfcd6SJosh Poimboeuf	cmd+=("--silent")
470*24ebfcd6SJosh Poimboeuf	cmd+=("-j$JOBS")
471*24ebfcd6SJosh Poimboeuf	cmd+=("clean")
472*24ebfcd6SJosh Poimboeuf
473*24ebfcd6SJosh Poimboeuf	(
474*24ebfcd6SJosh Poimboeuf		cd "$SRC"
475*24ebfcd6SJosh Poimboeuf		"${cmd[@]}"
476*24ebfcd6SJosh Poimboeuf	)
477*24ebfcd6SJosh Poimboeuf}
478*24ebfcd6SJosh Poimboeuf
479*24ebfcd6SJosh Poimboeufbuild_kernel() {
480*24ebfcd6SJosh Poimboeuf	local log="$TMP_DIR/build.log"
481*24ebfcd6SJosh Poimboeuf	local cmd=()
482*24ebfcd6SJosh Poimboeuf
483*24ebfcd6SJosh Poimboeuf	cmd=("make")
484*24ebfcd6SJosh Poimboeuf
485*24ebfcd6SJosh Poimboeuf	# When a patch to a kernel module references a newly created unexported
486*24ebfcd6SJosh Poimboeuf	# symbol which lives in vmlinux or another kernel module, the patched
487*24ebfcd6SJosh Poimboeuf	# kernel build fails with the following error:
488*24ebfcd6SJosh Poimboeuf	#
489*24ebfcd6SJosh Poimboeuf	#   ERROR: modpost: "klp_string" [fs/xfs/xfs.ko] undefined!
490*24ebfcd6SJosh Poimboeuf	#
491*24ebfcd6SJosh Poimboeuf	# The undefined symbols are working as designed in that case.  They get
492*24ebfcd6SJosh Poimboeuf	# resolved later when the livepatch module build link pulls all the
493*24ebfcd6SJosh Poimboeuf	# disparate objects together into the same kernel module.
494*24ebfcd6SJosh Poimboeuf	#
495*24ebfcd6SJosh Poimboeuf	# It would be good to have a way to tell modpost to skip checking for
496*24ebfcd6SJosh Poimboeuf	# undefined symbols altogether.  For now, just convert the error to a
497*24ebfcd6SJosh Poimboeuf	# warning with KBUILD_MODPOST_WARN, and grep out the warning to avoid
498*24ebfcd6SJosh Poimboeuf	# confusing the user.
499*24ebfcd6SJosh Poimboeuf	#
500*24ebfcd6SJosh Poimboeuf	cmd+=("KBUILD_MODPOST_WARN=1")
501*24ebfcd6SJosh Poimboeuf
502*24ebfcd6SJosh Poimboeuf	cmd+=("$VERBOSE")
503*24ebfcd6SJosh Poimboeuf	cmd+=("-j$JOBS")
504*24ebfcd6SJosh Poimboeuf	cmd+=("KCFLAGS=-ffunction-sections -fdata-sections")
505*24ebfcd6SJosh Poimboeuf	cmd+=("vmlinux")
506*24ebfcd6SJosh Poimboeuf	cmd+=("modules")
507*24ebfcd6SJosh Poimboeuf
508*24ebfcd6SJosh Poimboeuf	(
509*24ebfcd6SJosh Poimboeuf		cd "$SRC"
510*24ebfcd6SJosh Poimboeuf		"${cmd[@]}"							\
511*24ebfcd6SJosh Poimboeuf			1> >(tee -a "$log")					\
512*24ebfcd6SJosh Poimboeuf			2> >(tee -a "$log" | grep0 -v "modpost.*undefined!" >&2)
513*24ebfcd6SJosh Poimboeuf	)
514*24ebfcd6SJosh Poimboeuf}
515*24ebfcd6SJosh Poimboeuf
516*24ebfcd6SJosh Poimboeuffind_objects() {
517*24ebfcd6SJosh Poimboeuf	local opts=("$@")
518*24ebfcd6SJosh Poimboeuf
519*24ebfcd6SJosh Poimboeuf	# Find root-level vmlinux.o and non-root-level .ko files,
520*24ebfcd6SJosh Poimboeuf	# excluding klp-tmp/ and .git/
521*24ebfcd6SJosh Poimboeuf	find "$OBJ" \( -path "$TMP_DIR" -o -path "$OBJ/.git" -o	-regex "$OBJ/[^/][^/]*\.ko" \) -prune -o \
522*24ebfcd6SJosh Poimboeuf		    -type f "${opts[@]}"				\
523*24ebfcd6SJosh Poimboeuf		    \( -name "*.ko" -o -path "$OBJ/vmlinux.o" \)	\
524*24ebfcd6SJosh Poimboeuf		    -printf '%P\n'
525*24ebfcd6SJosh Poimboeuf}
526*24ebfcd6SJosh Poimboeuf
527*24ebfcd6SJosh Poimboeuf# Copy all .o archives to $ORIG_DIR
528*24ebfcd6SJosh Poimboeufcopy_orig_objects() {
529*24ebfcd6SJosh Poimboeuf	local files=()
530*24ebfcd6SJosh Poimboeuf
531*24ebfcd6SJosh Poimboeuf	rm -rf "$ORIG_DIR"
532*24ebfcd6SJosh Poimboeuf	mkdir -p "$ORIG_DIR"
533*24ebfcd6SJosh Poimboeuf
534*24ebfcd6SJosh Poimboeuf	find_objects | mapfile -t files
535*24ebfcd6SJosh Poimboeuf
536*24ebfcd6SJosh Poimboeuf	xtrace_save "copying orig objects"
537*24ebfcd6SJosh Poimboeuf	for _file in "${files[@]}"; do
538*24ebfcd6SJosh Poimboeuf		local rel_file="${_file/.ko/.o}"
539*24ebfcd6SJosh Poimboeuf		local file="$OBJ/$rel_file"
540*24ebfcd6SJosh Poimboeuf		local file_dir="$(dirname "$file")"
541*24ebfcd6SJosh Poimboeuf		local orig_file="$ORIG_DIR/$rel_file"
542*24ebfcd6SJosh Poimboeuf		local orig_dir="$(dirname "$orig_file")"
543*24ebfcd6SJosh Poimboeuf		local cmd_file="$file_dir/.$(basename "$file").cmd"
544*24ebfcd6SJosh Poimboeuf
545*24ebfcd6SJosh Poimboeuf		[[ ! -f "$file" ]] && die "missing $(basename "$file") for $_file"
546*24ebfcd6SJosh Poimboeuf
547*24ebfcd6SJosh Poimboeuf		mkdir -p "$orig_dir"
548*24ebfcd6SJosh Poimboeuf		cp -f "$file" "$orig_dir"
549*24ebfcd6SJosh Poimboeuf		[[ -e "$cmd_file" ]] && cp -f "$cmd_file" "$orig_dir"
550*24ebfcd6SJosh Poimboeuf	done
551*24ebfcd6SJosh Poimboeuf	xtrace_restore
552*24ebfcd6SJosh Poimboeuf
553*24ebfcd6SJosh Poimboeuf	mv -f "$TMP_DIR/build.log" "$ORIG_DIR"
554*24ebfcd6SJosh Poimboeuf	touch "$TIMESTAMP"
555*24ebfcd6SJosh Poimboeuf}
556*24ebfcd6SJosh Poimboeuf
557*24ebfcd6SJosh Poimboeuf# Copy all changed objects to $PATCHED_DIR
558*24ebfcd6SJosh Poimboeufcopy_patched_objects() {
559*24ebfcd6SJosh Poimboeuf	local files=()
560*24ebfcd6SJosh Poimboeuf	local opts=()
561*24ebfcd6SJosh Poimboeuf	local found=0
562*24ebfcd6SJosh Poimboeuf
563*24ebfcd6SJosh Poimboeuf	rm -rf "$PATCHED_DIR"
564*24ebfcd6SJosh Poimboeuf	mkdir -p "$PATCHED_DIR"
565*24ebfcd6SJosh Poimboeuf
566*24ebfcd6SJosh Poimboeuf	# Note this doesn't work with some configs, thus the 'cmp' below.
567*24ebfcd6SJosh Poimboeuf	opts=("-newer")
568*24ebfcd6SJosh Poimboeuf	opts+=("$TIMESTAMP")
569*24ebfcd6SJosh Poimboeuf
570*24ebfcd6SJosh Poimboeuf	find_objects "${opts[@]}" | mapfile -t files
571*24ebfcd6SJosh Poimboeuf
572*24ebfcd6SJosh Poimboeuf	xtrace_save "copying changed objects"
573*24ebfcd6SJosh Poimboeuf	for _file in "${files[@]}"; do
574*24ebfcd6SJosh Poimboeuf		local rel_file="${_file/.ko/.o}"
575*24ebfcd6SJosh Poimboeuf		local file="$OBJ/$rel_file"
576*24ebfcd6SJosh Poimboeuf		local orig_file="$ORIG_DIR/$rel_file"
577*24ebfcd6SJosh Poimboeuf		local patched_file="$PATCHED_DIR/$rel_file"
578*24ebfcd6SJosh Poimboeuf		local patched_dir="$(dirname "$patched_file")"
579*24ebfcd6SJosh Poimboeuf
580*24ebfcd6SJosh Poimboeuf		[[ ! -f "$file" ]] && die "missing $(basename "$file") for $_file"
581*24ebfcd6SJosh Poimboeuf
582*24ebfcd6SJosh Poimboeuf		cmp -s "$orig_file" "$file" && continue
583*24ebfcd6SJosh Poimboeuf
584*24ebfcd6SJosh Poimboeuf		mkdir -p "$patched_dir"
585*24ebfcd6SJosh Poimboeuf		cp -f "$file" "$patched_dir"
586*24ebfcd6SJosh Poimboeuf		found=1
587*24ebfcd6SJosh Poimboeuf	done
588*24ebfcd6SJosh Poimboeuf	xtrace_restore
589*24ebfcd6SJosh Poimboeuf
590*24ebfcd6SJosh Poimboeuf	(( found == 0 )) && die "no changes detected"
591*24ebfcd6SJosh Poimboeuf
592*24ebfcd6SJosh Poimboeuf	mv -f "$TMP_DIR/build.log" "$PATCHED_DIR"
593*24ebfcd6SJosh Poimboeuf}
594*24ebfcd6SJosh Poimboeuf
595*24ebfcd6SJosh Poimboeuf# Diff changed objects, writing output object to $DIFF_DIR
596*24ebfcd6SJosh Poimboeufdiff_objects() {
597*24ebfcd6SJosh Poimboeuf	local log="$KLP_DIFF_LOG"
598*24ebfcd6SJosh Poimboeuf	local files=()
599*24ebfcd6SJosh Poimboeuf
600*24ebfcd6SJosh Poimboeuf	rm -rf "$DIFF_DIR"
601*24ebfcd6SJosh Poimboeuf	mkdir -p "$DIFF_DIR"
602*24ebfcd6SJosh Poimboeuf
603*24ebfcd6SJosh Poimboeuf	find "$PATCHED_DIR" -type f -name "*.o" | mapfile -t files
604*24ebfcd6SJosh Poimboeuf	[[ ${#files[@]} -eq 0 ]] && die "no changes detected"
605*24ebfcd6SJosh Poimboeuf
606*24ebfcd6SJosh Poimboeuf	# Diff all changed objects
607*24ebfcd6SJosh Poimboeuf	for file in "${files[@]}"; do
608*24ebfcd6SJosh Poimboeuf		local rel_file="${file#"$PATCHED_DIR"/}"
609*24ebfcd6SJosh Poimboeuf		local orig_file="$rel_file"
610*24ebfcd6SJosh Poimboeuf		local patched_file="$PATCHED_DIR/$rel_file"
611*24ebfcd6SJosh Poimboeuf		local out_file="$DIFF_DIR/$rel_file"
612*24ebfcd6SJosh Poimboeuf		local cmd=()
613*24ebfcd6SJosh Poimboeuf
614*24ebfcd6SJosh Poimboeuf		mkdir -p "$(dirname "$out_file")"
615*24ebfcd6SJosh Poimboeuf
616*24ebfcd6SJosh Poimboeuf		cmd=("$SRC/tools/objtool/objtool")
617*24ebfcd6SJosh Poimboeuf		cmd+=("klp")
618*24ebfcd6SJosh Poimboeuf		cmd+=("diff")
619*24ebfcd6SJosh Poimboeuf		cmd+=("$orig_file")
620*24ebfcd6SJosh Poimboeuf		cmd+=("$patched_file")
621*24ebfcd6SJosh Poimboeuf		cmd+=("$out_file")
622*24ebfcd6SJosh Poimboeuf
623*24ebfcd6SJosh Poimboeuf		(
624*24ebfcd6SJosh Poimboeuf			cd "$ORIG_DIR"
625*24ebfcd6SJosh Poimboeuf			"${cmd[@]}"							\
626*24ebfcd6SJosh Poimboeuf				1> >(tee -a "$log")					\
627*24ebfcd6SJosh Poimboeuf				2> >(tee -a "$log" >&2) ||				\
628*24ebfcd6SJosh Poimboeuf				die "objtool klp diff failed"
629*24ebfcd6SJosh Poimboeuf		)
630*24ebfcd6SJosh Poimboeuf	done
631*24ebfcd6SJosh Poimboeuf}
632*24ebfcd6SJosh Poimboeuf
633*24ebfcd6SJosh Poimboeuf# Build and post-process livepatch module in $KMOD_DIR
634*24ebfcd6SJosh Poimboeufbuild_patch_module() {
635*24ebfcd6SJosh Poimboeuf	local makefile="$KMOD_DIR/Kbuild"
636*24ebfcd6SJosh Poimboeuf	local log="$KMOD_DIR/build.log"
637*24ebfcd6SJosh Poimboeuf	local kmod_file
638*24ebfcd6SJosh Poimboeuf	local cflags=()
639*24ebfcd6SJosh Poimboeuf	local files=()
640*24ebfcd6SJosh Poimboeuf	local cmd=()
641*24ebfcd6SJosh Poimboeuf
642*24ebfcd6SJosh Poimboeuf	rm -rf "$KMOD_DIR"
643*24ebfcd6SJosh Poimboeuf	mkdir -p "$KMOD_DIR"
644*24ebfcd6SJosh Poimboeuf
645*24ebfcd6SJosh Poimboeuf	cp -f "$SRC/scripts/livepatch/init.c" "$KMOD_DIR"
646*24ebfcd6SJosh Poimboeuf
647*24ebfcd6SJosh Poimboeuf	echo "obj-m := $NAME.o" > "$makefile"
648*24ebfcd6SJosh Poimboeuf	echo -n "$NAME-y := init.o" >> "$makefile"
649*24ebfcd6SJosh Poimboeuf
650*24ebfcd6SJosh Poimboeuf	find "$DIFF_DIR" -type f -name "*.o" | mapfile -t files
651*24ebfcd6SJosh Poimboeuf	[[ ${#files[@]} -eq 0 ]] && die "no changes detected"
652*24ebfcd6SJosh Poimboeuf
653*24ebfcd6SJosh Poimboeuf	for file in "${files[@]}"; do
654*24ebfcd6SJosh Poimboeuf		local rel_file="${file#"$DIFF_DIR"/}"
655*24ebfcd6SJosh Poimboeuf		local orig_file="$ORIG_DIR/$rel_file"
656*24ebfcd6SJosh Poimboeuf		local orig_dir="$(dirname "$orig_file")"
657*24ebfcd6SJosh Poimboeuf		local kmod_file="$KMOD_DIR/$rel_file"
658*24ebfcd6SJosh Poimboeuf		local kmod_dir="$(dirname "$kmod_file")"
659*24ebfcd6SJosh Poimboeuf		local cmd_file="$orig_dir/.$(basename "$file").cmd"
660*24ebfcd6SJosh Poimboeuf
661*24ebfcd6SJosh Poimboeuf		mkdir -p "$kmod_dir"
662*24ebfcd6SJosh Poimboeuf		cp -f "$file" "$kmod_dir"
663*24ebfcd6SJosh Poimboeuf		[[ -e "$cmd_file" ]] && cp -f "$cmd_file" "$kmod_dir"
664*24ebfcd6SJosh Poimboeuf
665*24ebfcd6SJosh Poimboeuf		# Tell kbuild this is a prebuilt object
666*24ebfcd6SJosh Poimboeuf		cp -f "$file" "${kmod_file}_shipped"
667*24ebfcd6SJosh Poimboeuf
668*24ebfcd6SJosh Poimboeuf		echo -n " $rel_file" >> "$makefile"
669*24ebfcd6SJosh Poimboeuf	done
670*24ebfcd6SJosh Poimboeuf
671*24ebfcd6SJosh Poimboeuf	echo >> "$makefile"
672*24ebfcd6SJosh Poimboeuf
673*24ebfcd6SJosh Poimboeuf	cflags=("-ffunction-sections")
674*24ebfcd6SJosh Poimboeuf	cflags+=("-fdata-sections")
675*24ebfcd6SJosh Poimboeuf	[[ $REPLACE -eq 0 ]] && cflags+=("-DKLP_NO_REPLACE")
676*24ebfcd6SJosh Poimboeuf
677*24ebfcd6SJosh Poimboeuf	cmd=("make")
678*24ebfcd6SJosh Poimboeuf	cmd+=("$VERBOSE")
679*24ebfcd6SJosh Poimboeuf	cmd+=("-j$JOBS")
680*24ebfcd6SJosh Poimboeuf	cmd+=("--directory=.")
681*24ebfcd6SJosh Poimboeuf	cmd+=("M=$KMOD_DIR")
682*24ebfcd6SJosh Poimboeuf	cmd+=("KCFLAGS=${cflags[*]}")
683*24ebfcd6SJosh Poimboeuf
684*24ebfcd6SJosh Poimboeuf	# Build a "normal" kernel module with init.c and the diffed objects
685*24ebfcd6SJosh Poimboeuf	(
686*24ebfcd6SJosh Poimboeuf		cd "$SRC"
687*24ebfcd6SJosh Poimboeuf		"${cmd[@]}"							\
688*24ebfcd6SJosh Poimboeuf			1> >(tee -a "$log")					\
689*24ebfcd6SJosh Poimboeuf			2> >(tee -a "$log" >&2)
690*24ebfcd6SJosh Poimboeuf	)
691*24ebfcd6SJosh Poimboeuf
692*24ebfcd6SJosh Poimboeuf	kmod_file="$KMOD_DIR/$NAME.ko"
693*24ebfcd6SJosh Poimboeuf
694*24ebfcd6SJosh Poimboeuf	# Save off the intermediate binary for debugging
695*24ebfcd6SJosh Poimboeuf	cp -f "$kmod_file" "$kmod_file.orig"
696*24ebfcd6SJosh Poimboeuf
697*24ebfcd6SJosh Poimboeuf	# Work around issue where slight .config change makes corrupt BTF
698*24ebfcd6SJosh Poimboeuf	objcopy --remove-section=.BTF "$kmod_file"
699*24ebfcd6SJosh Poimboeuf
700*24ebfcd6SJosh Poimboeuf	# Fix (and work around) linker wreckage for klp syms / relocs
701*24ebfcd6SJosh Poimboeuf	"$SRC/tools/objtool/objtool" klp post-link "$kmod_file" || die "objtool klp post-link failed"
702*24ebfcd6SJosh Poimboeuf
703*24ebfcd6SJosh Poimboeuf	cp -f "$kmod_file" "$OUTFILE"
704*24ebfcd6SJosh Poimboeuf}
705*24ebfcd6SJosh Poimboeuf
706*24ebfcd6SJosh Poimboeuf
707*24ebfcd6SJosh Poimboeuf################################################################################
708*24ebfcd6SJosh Poimboeuf
709*24ebfcd6SJosh Poimboeufprocess_args "$@"
710*24ebfcd6SJosh Poimboeufdo_init
711*24ebfcd6SJosh Poimboeuf
712*24ebfcd6SJosh Poimboeufif (( SHORT_CIRCUIT <= 1 )); then
713*24ebfcd6SJosh Poimboeuf	status "Validating patch(es)"
714*24ebfcd6SJosh Poimboeuf	validate_patches
715*24ebfcd6SJosh Poimboeuf	status "Building original kernel"
716*24ebfcd6SJosh Poimboeuf	clean_kernel
717*24ebfcd6SJosh Poimboeuf	build_kernel
718*24ebfcd6SJosh Poimboeuf	status "Copying original object files"
719*24ebfcd6SJosh Poimboeuf	copy_orig_objects
720*24ebfcd6SJosh Poimboeuffi
721*24ebfcd6SJosh Poimboeuf
722*24ebfcd6SJosh Poimboeufif (( SHORT_CIRCUIT <= 2 )); then
723*24ebfcd6SJosh Poimboeuf	status "Fixing patch(es)"
724*24ebfcd6SJosh Poimboeuf	fix_patches
725*24ebfcd6SJosh Poimboeuf	apply_patches
726*24ebfcd6SJosh Poimboeuf	status "Building patched kernel"
727*24ebfcd6SJosh Poimboeuf	build_kernel
728*24ebfcd6SJosh Poimboeuf	revert_patches
729*24ebfcd6SJosh Poimboeuf	status "Copying patched object files"
730*24ebfcd6SJosh Poimboeuf	copy_patched_objects
731*24ebfcd6SJosh Poimboeuffi
732*24ebfcd6SJosh Poimboeuf
733*24ebfcd6SJosh Poimboeufif (( SHORT_CIRCUIT <= 3 )); then
734*24ebfcd6SJosh Poimboeuf	status "Diffing objects"
735*24ebfcd6SJosh Poimboeuf	diff_objects
736*24ebfcd6SJosh Poimboeuffi
737*24ebfcd6SJosh Poimboeuf
738*24ebfcd6SJosh Poimboeufif (( SHORT_CIRCUIT <= 4 )); then
739*24ebfcd6SJosh Poimboeuf	status "Building patch module: $OUTFILE"
740*24ebfcd6SJosh Poimboeuf	build_patch_module
741*24ebfcd6SJosh Poimboeuffi
742*24ebfcd6SJosh Poimboeuf
743*24ebfcd6SJosh Poimboeufstatus "SUCCESS"
744