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